Wie extrahiere ich den Inhalt von Strings in Anführungszeichen aus der Ausgabe eines Befehls?

26

Ich habe eine Ausgabe, VBoxManage list vmsdie so aussieht:

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

Ich brauche die Namen zu greifen archund arch2und sie in eine Variable speichern.

Harrys Kavan
quelle

Antworten:

34

Mit grep + sed

Dadurch wird der Inhalt dieser beiden Zeichenfolgen analysiert:

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

Oben wird nach einer Zeichenfolge gesucht, die dem Muster entspricht ".*". Das passt zu allem, was in doppelten Anführungszeichen steht. So grepwerden diese Arten von Werten zurückgegeben:

"arch"
"arch2"

Die Pipe zum sedEntfernen von doppelten Anführungszeichen aus diesen Zeichenfolgen gibt Ihnen die Zeichenfolgen, nach denen Sie suchen. In der Notation sed 's/"//g'wird angewiesen sed, alle doppelten Anführungszeichen zu suchen und durch nichts zu ersetzen s/"//g. Der Befehl s/find/replace/gist das, was dort vor sich geht, und der gSuchpfad weist ihn an, dies global für die gesamte angegebene Zeichenfolge zu tun.

Mit nur sed

Sie können auch verwenden sed, um das anfängliche doppelte Anführungszeichen abzuschneiden, den Abstand zwischen ihnen beizubehalten und das verbleibende Anführungszeichen abzubrechen.

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

Andere Methoden

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

Mit dem Befehl trkönnen Zeichen gelöscht werden. In diesem Fall werden die doppelten Anführungszeichen gelöscht.

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

Mit grepder PCRE-Funktion von können Sie nach Unterzeichenfolgen suchen, die mit einem doppelten Anführungszeichen beginnen oder mit einem doppelten Anführungszeichen enden, und nur die Unterzeichenfolge melden.

slm
quelle
1
tr -d \"ist eine andere Möglichkeit, die Anführungszeichen zu löschen. ( trÜbersetzt normalerweise einen Zeichensatz in einen anderen; -d
fordert
1
slm - Wenn Sie ein /address/to sedlike hinzufügen , können sed '/^"\(arch[^"]*\)/s//\1/Sie nur Zeilen bearbeiten , die diesen String enthalten.
mikeserv
1
@mikeserv - wahr, ich war mir nicht sicher, wie konsistent der Bogen in seiner Ausgabe sein würde. Aber wenn ja, dann würde das auch funktionieren.
slm
1
guter Punkt slm. Es gibt keinen Hinweis darauf, dass dies konsistent sein wird. Es tut uns leid.
mikeserv
2
Ich habe aber gerade gemerkt, dass Sie das sedwirklich tun sollten, s/^"\([^"]*\)".*/\1/nur für den Fall, dass nur zwei doppelte Anführungszeichen in der Zeile stehen.
mikeserv
19

Das ist ein weiterer Job für cut:

VBoxManage list vms | cut -d \" -f2
Stéphane Chazelas
quelle
3
Sehr gepflegt! So funktioniert es: cutTeilt jede Zeile in Felder unter Verwendung des Anführungszeichens als Trennzeichen und gibt dann Feld 2 aus: Feld 1 ist die leere Zeichenfolge vor dem ersten Anführungszeichen, Feld 2 ist die gewünschte Zeichenfolge zwischen den Anführungszeichen und Feld 3 ist der Rest der Linie.
Deltab
7

Mit sedkönnen Sie:

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

Erläuterung:

  • s/.../.../ - anpassen und ersetzen
  • ^- Spiel am Zeilenanfang
  • \(...\) - Dies ist eine Rückreferenz, wir können auf das verweisen, was hier später mit übereinstimmt \1
  • [^"]*- Übereinstimmung mit einer Sequenz, die kein a enthält "(dh bis zur nächsten)" )
  • .* - Passen Sie den Rest der Linie an
  • \1 - durch die rückseitige Referenz ersetzen

Oder mit awk:

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

Beachten Sie, dass Sie in modernen Shells anstelle einer normalen Variablen auch ein Array verwenden können. In können bashSie tun:

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

Dies ist möglicherweise einfacher, wenn Sie die Variable verwenden.

Graeme
quelle
Würdest du bitte diesen sed Befehl für mich brechen?
Harrys Kavan
5

Mit bash würde ich schreiben:

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
quelle
5

Und die durch Grep Oneliner mit --perl-regexpOption,

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

Erläuterung:

(?<=^\")[^"]*-> Hier wird ein Lookbehind verwendet. Es stimmt mit jedem Zeichen überein, jedoch nicht mit "null oder mehreren Übereinstimmungen (sobald es doppelte Anführungszeichen findet, hört es auf, übereinzustimmen), die direkt nach doppelten Anführungszeichen stehen (nur die Zeile, die mit doppelten Anführungszeichen beginnt).

Ein weiterer hässlicher Hack durch sed,

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

Da Regex gierige und nicht gierige Modi hat, würde es nicht wie gewünscht extrahiert, wenn Sie mehrere Ziele in derselben Zeile haben. Linie:

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

Ziel:

tom
jerry

Befehl (gieriger Modus):

grep -oP '".*"' name

Befehl (nicht gieriger Modus):

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