Jak wyodrębnić treść cytowanych ciągów z danych wyjściowych polecenia?


26

Mam dane wyjściowe, z VBoxManage list vmsktórych wygląda to tak:

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

Muszę złapać nazwy archi arch2i zapisać je w zmiennej.

Odpowiedzi:


34

Używanie grep + sed

Spowoduje to przeanalizowanie zawartości tych 2 ciągów:

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

Powyższe wygląda na ciąg pasujący do wzoru ".*". To pasuje do wszystkiego, co występuje w obrębie podwójnych cudzysłowów. Więc grepzwrócą te typy wartości:

"arch"
"arch2"

Rura do sedusunie wszelkie podwójne cudzysłowy z tych ciągów, dając ciągi, których szukasz. Zapis sed 's/"//g'jest instruowanie sedzrobić wyszukiwania i zamiany na wszystkie wystąpienia cudzysłowach, zastępując je z niczego s/"//g. Polecenie s/find/replace/gjest tym, co się tam dzieje, a gciąg wyszukiwania służy do tego, aby zrobić to globalnie na całym podanym ciągu.

Używam tylko sed

Możesz także użyć seddo odcięcia początkowego podwójnego cytatu, zatrzymania tego, co jest między nimi, i odcięcia pozostałego cytatu + wszystkiego po nim:

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

Inne metody

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

Polecenia trmożna używać do usuwania znaków. W tym przypadku usuwa podwójne cudzysłowy.

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

Korzystając grepz funkcji PCRE możesz wyszukać dowolne podciągi, które zaczynają się od podwójnego cudzysłowu lub kończą podwójnym cudzysłowiem i zgłaszają tylko podłańcuchy.


1
tr -d \"to kolejny sposób na usunięcie cytatów. ( trzwykle tłumaczy jeden zestaw znaków na inny; -dkaże mu je po prostu usunąć).
deltab

1
SLM - jeśli dodasz /address/do sedjak sed '/^"\(arch[^"]*\)/s//\1/będziesz pracować wyłącznie na liniach zawierających ten ciąg.
mikeserv

1
@ mikeserv - prawda, nie byłem pewien, jak spójny będzie łuk w jego wynikach. Ale jeśli tak, to też by to działało.
slm

1
dobry punkt slm. Nic nie wskazuje na to, by było spójne. Przepraszam.
mikeserv

2
Właśnie zdałem sobie sprawę, że sednaprawdę powinieneś robić s/^"\([^"]*\)".*/\1/na wypadek, gdyby na linii były tylko dwa podwójne cudzysłowy.
mikeserv

19

To kolejna praca dla cut:

VBoxManage list vms | cut -d \" -f2

3
Bardzo schludny! Jak to działa: cutdzieli każdą linię na pola przy użyciu znaku cudzysłowu jako separatora, a następnie wypisuje pole 2: pole 1 jest pustym ciągiem przed pierwszym cytatem, pole 2 jest poszukiwanym ciągiem między cytatami, a pole 3 jest resztą linia.
deltab

7

Dzięki sedniemu możesz:

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

Wyjaśnienie:

  • s/.../.../ - dopasuj i zamień
  • ^- mecz na początku linii
  • \(...\) - jest to odniesienie wstecz, możemy odwołać się do tego, co jest tutaj dopasowane później \1
  • [^"]*- dopasuj dowolną sekwencję, która nie zawiera "(tj. do następnej ")
  • .* - dopasuj do reszty linii
  • \1 - zastąpić referencją wsteczną

Lub z awk:

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

Zauważ, że we współczesnych powłokach możesz także użyć tablicy zamiast normalnej zmiennej. W bashmożna zrobić:

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

To może być łatwiejsze, gdy przychodzi się do użycia zmiennej.


Czy mógłbyś złamać to polecenie sed dla mnie, proszę?
Harrys Kavan

5

Używając bash, napisałbym:

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

5

I ten przez grep oneliner z --perl-regexpopcją,

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

Wyjaśnienie:

(?<=^\")[^"]*-> Tutaj jest używany wygląd. Dopasowuje dowolny znak, ale nie "zero lub więcej razy (gdy znajdzie podwójne cudzysłowy, przestaje się dopasowywać), które są tuż po podwójnych cudzysłowach (tylko wiersz zaczynający się od podwójnych cudzysłowów).

Kolejny brzydki włam sed,

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

0

ponieważ regex ma tryby chciwości i chciwości, jeśli masz wiele celów w tej samej linii, nie wyodrębni się tak, jak chcesz. Linia:

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

Cel:

tom
jerry

Polecenie (tryb zachłanny):

grep -oP '".*"' name

Polecenie (tryb bez chciwości):

grep -oP '".*?"' name
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.