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

26

J'ai une sortie VBoxManage list vmsqui ressemble à ceci:

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

Je dois saisir les noms archet arch2et les enregistrer dans une variable.

Harrys Kavan
la source

Réponses:

34

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. Ainsi grep, ces types de valeurs seront renvoyés:

"arch"
"arch2"

Le tuyau à sedsupprimer toutes les guillemets doubles de ces chaînes en vous donnant les chaînes que vous recherchez. La notation sed 's/"//g'est instruisait sedde faire une recherche et remplacer sur toutes les occurrences de guillemets doubles, les remplacer par rien, s/"//g. La commande s/find/replace/gest ce qui se passe là-bas, et la fin gde la recherche lui dit de le faire globalement sur toute la chaîne qui lui est donnée.

Utilisation de sed

Vous pouvez également utiliser sedpour couper le guillemet double de début, conserver ce qui se trouve entre les deux et couper le devis restant + 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 trpeut être utilisée pour supprimer des caractères. Dans ce cas, il supprime les guillemets doubles.

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

En utilisant grepla fonction PCRE de, vous pouvez rechercher toutes les sous-chaînes commençant par un guillemet double ou se terminant par un guillemet double et signaler uniquement la sous-chaîne.

slm
la source
1
tr -d \"est une autre façon de supprimer les guillemets. ( trtraduit normalement un jeu de caractères en un autre; lui -ddit de simplement les supprimer à la place.)
deltab
1
slm - si vous ajoutez un /address/to sedlike, sed '/^"\(arch[^"]*\)/s//\1/vous n'opérerez que sur les lignes contenant cette chaîne.
mikeserv
1
@mikeserv - vrai, je n'étais pas sûr de la cohérence de l'arc dans sa sortie. Mais si c'est le cas, cela fonctionnerait aussi.
slm
1
bon point slm. Rien n'indique que ce sera cohérent. Désolé.
mikeserv
2
Je viens juste de réaliser que vous seddevriez vraiment faire s/^"\([^"]*\)".*/\1/au cas où il n'y aurait que deux guillemets sur la ligne.
mikeserv
19

C'est un autre travail pour cut:

VBoxManage list vms | cut -d \" -f2
Stéphane Chazelas
la source
3
Très propre! Fonctionnement: cutdivise chaque ligne en champs en utilisant le guillemet comme délimiteur, puis affiche le champ 2: le champ 1 est la chaîne vide avant le premier devis, le champ 2 est la chaîne souhaitée entre les guillemets et le champ 3 est le reste de la ligne.
deltab
7

Avec sedvous pouvez faire:

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

Explication:

  • s/.../.../ - correspondre et remplacer
  • ^- match en début de ligne
  • \(...\) - ceci est une référence arrière, nous pouvons nous référer à ce qui est apparié ici plus tard avec \1
  • [^"]*- correspondre à toute séquence qui ne contient pas de "(c'est-à-dire jusqu'à la suivante ")
  • .* - correspondre 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. En bashvous 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.

Graeme
la source
Souhaitez-vous rompre cette commande sed pour moi s'il vous plaît?
Harrys Kavan
5

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
glenn jackman
la source
5

Et celui via grep oneliner avec --perl-regexpoption,

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 se trouvent 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
Avinash Raj
la source
0

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
Tiina
la source