Come estraggo il contenuto delle stringhe tra virgolette dall'output di un comando?


26

Ho un output dal VBoxManage list vmsquale assomiglia a questo:

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

Ho bisogno di prendere i nomi arche arch2e salvarli in una variabile.

Risposte:


34

Utilizzando grep + sed

Questo analizzerà il contenuto di quelle 2 stringhe:

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

Quanto sopra cerca una stringa che corrisponda al modello ".*". Che corrisponderà a tutto ciò che accade tra virgolette doppie. Quindi greprestituirà questi tipi di valori:

"arch"
"arch2"

La pipe per sedrimuovere tutte le doppie virgolette da queste stringhe dando le stringhe che stai cercando. La notazione sed 's/"//g'indica seddi fare una ricerca e di sostituire tutte le occorrenze di virgolette doppie, sostituendole con nulla s/"//g. Il comando s/find/replace/gè quello che sta succedendo lì, e il trailing gda cercare gli dice di farlo globalmente sull'intera stringa che gli viene data.

Usando solo sed

Puoi anche usare sedper tagliare la doppia citazione iniziale, mantenere ciò che c'è tra loro e tagliare la citazione rimanente + tutto ciò che segue:

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

Altri metodi

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

Il comando trpuò essere utilizzato per eliminare caratteri. In questo caso sta eliminando le doppie virgolette.

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

Usando grepla funzione PCRE puoi cercare tutte le sottostringhe che iniziano con una doppia citazione o terminano con una doppia citazione e riportano solo la sottostringa.


1
tr -d \"è un altro modo per eliminare le virgolette. (di trsolito traduce un set di caratteri in un altro; -ddice invece di eliminarli invece.)
deltab

1
SLM - se si aggiunge un /address/per sedcome sed '/^"\(arch[^"]*\)/s//\1/potrai operare solo sulle linee che contengono quella stringa.
Mikeserv,

1
@mikeserv - vero, non ero sicuro di quanto sarebbe stato coerente l'arco nella sua uscita. Ma se lo è, funzionerebbe anche quello.
slm

1
buon punto slm. Non ci sono indicazioni che saranno coerenti. Scusate.
Mikeserv,

2
Mi sono appena reso conto che seddovresti davvero farlo s/^"\([^"]*\)".*/\1/nel caso in cui ci siano solo due doppie virgolette sulla riga.
Mikeserv,

19

Questo è un altro lavoro per cut:

VBoxManage list vms | cut -d \" -f2

3
Molto pulito! Come funziona: cutsuddivide ogni riga in campi usando il segno di virgolette come delimitatore, quindi genera il campo 2: il campo 1 è la stringa vuota prima della prima citazione, il campo 2 è la stringa desiderata tra le virgolette e il campo 3 è il resto del linea.
deltab,

7

Con sedte puoi fare:

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

Spiegazione:

  • s/.../.../ - abbina e sostituisci
  • ^- partita all'inizio della riga
  • \(...\) - questo è un riferimento indietro, possiamo fare riferimento a ciò che verrà abbinato qui in seguito con \1
  • [^"]*- corrisponde a qualsiasi sequenza che non contiene un "(cioè fino alla successiva ")
  • .* - abbina il resto della linea
  • \1 - sostituire con il riferimento posteriore

O con awk:

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

Nota che nelle shell moderne puoi anche usare un array invece di una normale variabile. In bashpuoi fare:

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

Questo potrebbe essere più semplice quando si utilizza la variabile.


Per favore, spezzeresti quel comando sed per me?
Harrys Kavan,

5

Usando bash, scriverei:

while read vm value; do
    case $vm in
        '"arch"') arch=$value ;;
        '"arch2"') arch2=$value ;;
    esac
done < <( VBoxManage list vms )
echo $arch
echo $arch2

5

E quello attraverso grep oneliner con --perl-regexpopzione,

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

Spiegazione:

(?<=^\")[^"]*-> Qui viene utilizzato un lookbehind. "Corrisponde a qualsiasi carattere ma non di zero o più volte (una volta trovata una virgoletta doppia, interrompe la corrispondenza) che sono subito dopo le virgolette doppie (solo la riga che inizia con le virgolette doppie).

Un altro brutto hack sed,

$ sed '/.*\"\(.*\)\".*/ s//\1/g' file
arch
arch2

0

poiché regex ha modalità avide e non avide, se hai più bersagli sulla stessa linea, non si estrarrà come desideri. Linea:

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

Bersaglio:

tom
jerry

Comando (modalità golosa):

grep -oP '".*"' name

Comando (modalità non avida):

grep -oP '".*?"' name
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.