web-dev-qa-db-fra.com

Comment extraire le contenu des chaînes entre guillemets de la sortie d'une commande?

J'ai une sortie de VBoxManage list vms qui ressemble à ceci:

"Arch" {de1a1db2-86c5-43e7-a8de-a0031835f7a7}   
"Arch2" {92d8513c-f13e-41b5-97e2-2a6b17d47b67}  

Je dois saisir les noms Arch et Arch2 et les enregistrer dans une variable.

27
Harrys Kavan

Utilisation de grep + sed

Cela analysera le contenu de ces 2 chaînes:

$ grep -o '".*"' somefile | sed 's/"//g'
Arch
arch2

Ce qui précède recherche une chaîne correspondant au modèle ".*". Cela correspondra à tout ce qui se produit entre guillemets doubles. Donc grep renverra ces types de valeurs:

"Arch"
"Arch2"

Le canal vers sed supprimera les guillemets doubles de ces chaînes, donnant ainsi les chaînes que vous recherchez. La notation sed 's/"//g' demande à sed d'effectuer une recherche et de remplacer toutes les occurrences de guillemets doubles, en les remplaçant par rien, s/"//g. La commande s/find/replace/g est ce qui se passe là-bas, et le dernier g à rechercher lui dit de le faire globalement sur toute la chaîne qui lui est donnée.

Utilisation de sed

Vous pouvez également utiliser sed pour couper le guillemet double de début, conserver ce qu'il y a entre eux et couper le reste du devis + tout ce qu'il y a après:

$ sed 's/^"\(.*\)".*/\1/' a
Arch
arch2

Autres méthodes

$ grep -o '".*"' somefile | tr -d '"'
Arch
arch2

La commande tr peut être utilisée pour supprimer des caractères. Dans ce cas, il supprime les guillemets doubles.

$ grep -oP '(?<=").*(?=")' somefile
Arch
arch2

En utilisant la fonction PCRE de grep, vous pouvez rechercher toutes les sous-chaînes qui commencent par un guillemet double ou se terminent par un guillemet double et signaler uniquement la sous-chaîne.

39
slm

C'est un autre travail pour cut:

VBoxManage list vms | cut -d \" -f2
21
Stéphane Chazelas

Avec sed vous pouvez faire:

var=$(VBoxManage list vms | sed 's/^"\([^"]*\).*/\1/')

Explication:

  • s/.../.../ - correspondre et remplacer
  • ^ - correspond au début de la ligne
  • \(...\) - il s'agit d'une référence arrière, nous pouvons faire référence à ce qui est mis en correspondance ici plus tard avec \1
  • [^"]* - correspond à toute séquence ne contenant pas de " (C.-à-d. Jusqu'à la prochaine ")
  • .* - correspond au reste de la ligne
  • \1 - remplacer par la référence arrière

Ou avec awk:

var=$(VBoxManage list vms | awk -F\" '{ print $2 }')

Notez que dans les shells modernes, vous pouvez également utiliser un tableau au lieu d'une variable normale. Dans bash, vous pouvez faire:

IFS=$'\n'; set -f
array=( $(VBoxManage list vms | awk -F\" '{ print $2 }') )
echo "array[0] = ${array[0]}"
echo "array[1] = ${array[1]}"

Cela pourrait être plus facile lorsque vous utilisez la variable.

7
Graeme

Et celui via grep oneliner avec --Perl-regexp option,

VBoxManage list vms | grep -oP '(?<=^\")[^"]*'

Explication:

(?<=^\")[^"]* -> Un lookbehind est utilisé ici. Il correspond à n'importe quel caractère mais pas à " zéro ou plusieurs fois (une fois qu'il trouve des guillemets doubles, il cesse de correspondre) qui sont juste après les guillemets doubles (uniquement la ligne qui commence par des guillemets doubles).

Un autre hack laid à travers sed,

$ sed '/.*\"\(.*\)\".*/ s//\1/g' file
Arch
arch2
6
Avinash Raj

En utilisant bash, j'écrirais:

while read vm value; do
    case $vm in
        '"Arch"') Arch=$value ;;
        '"Arch2"') Arch2=$value ;;
    esac
done < <( VBoxManage list vms )
echo $Arch
echo $Arch2
5
glenn jackman

puisque regex a des modes gourmands et non gourmands, si vous avez plusieurs cibles sur la même ligne, il ne sera pas extrait comme vous le souhaitez. Ligne:

"tom" is a cat, and "jerry" is a mouse. 

Cible:

tom
jerry

Commande (mode gourmand):

grep -oP '".*"' name

Commande (mode non gourmand):

grep -oP '".*?"' name
0
Tiina