Como extraio o conteúdo de seqüências de caracteres citadas da saída de um comando?

26

Eu tenho saída da VBoxManage list vmsqual se parece com isso:

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

Eu preciso pegar os nomes arche arch2e guardá-las em uma variável.

Harrys Kavan
fonte

Respostas:

34

Usando grep + sed

Isso analisará o conteúdo dessas duas strings:

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

O exemplo acima procura uma sequência que corresponda ao padrão ".*". Isso corresponderá a qualquer coisa que ocorra entre aspas duplas. Então grep, retornará esses tipos de valores:

"arch"
"arch2"

O tubo para sedretirar as aspas duplas dessas strings, fornecendo as strings que você está procurando. A notação sed 's/"//g'está instruindo seda fazer uma pesquisa e a substituir todas as ocorrências de aspas duplas, substituindo-as por nada s/"//g,. O comando s/find/replace/gé o que está acontecendo lá, e o rastreamento gda pesquisa diz para fazê-lo globalmente em toda a cadeia que é fornecida.

Usando apenas sed

Você também pode usar sedpara cortar a cotação dupla inicial, manter o que há entre elas e cortar a cotação restante + tudo o que há depois:

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

Outros métodos

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

O comando trpode ser usado para excluir caracteres. Nesse caso, está excluindo as aspas duplas.

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

Usando grepo recurso PCRE, você pode procurar por substrings que começam com aspas duplas ou terminam com aspas duplas e relatam apenas a substring.

slm
fonte
11
tr -d \"é outra maneira de excluir as aspas. ( trNormalmente traduz um conjunto de caracteres em outra, -ddiz-lhe para apenas excluí-los em vez disso.)
deltab
11
SLM - se você adicionar um /address/para sedcomo sed '/^"\(arch[^"]*\)/s//\1/você só vai operar em linhas que contenham essa string.
mikeserv
11
@mikeserv - verdade, não tinha certeza de quão consistente o arco seria em sua produção. Mas, se for, isso também funcionaria.
Slm
11
bom ponto slm. Não há indicação de que seja consistente. Desculpe.
mikeserv
2
Acabei de perceber que você sedrealmente deveria estar fazendo s/^"\([^"]*\)".*/\1/apenas no caso de haver apenas duas aspas duplas na linha.
mikeserv
19

Esse é outro trabalho para cut:

VBoxManage list vms | cut -d \" -f2
Stéphane Chazelas
fonte
3
Muito arrumado! Como funciona: cutdivide cada linha em campos usando as aspas como delimitador e, em seguida, gera o campo 2: o campo 1 é a sequência vazia antes da primeira cotação, o campo 2 é a sequência desejada entre as aspas e o campo 3 é o restante linha.
Deltab
7

Com sedvocê pode fazer:

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

Explicação:

  • s/.../.../ - combinar e substituir
  • ^- partida no início da linha
  • \(...\) - esta é uma referência anterior, podemos nos referir ao que corresponde aqui mais tarde com \1
  • [^"]*- corresponde a qualquer sequência que não contenha um "(ou seja, até a próxima ")
  • .* - corresponder ao resto da linha
  • \1 - substitua pela referência anterior

Ou com awk:

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

Observe que, nos shells modernos, você também pode usar uma matriz em vez de uma variável normal. Em bashvocê pode fazer:

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

Isso pode ser mais fácil quando você usa a variável.

Graeme
fonte
Você quebraria esse comando sed para mim, por favor?
Harrys Kavan
5

Usando o bash, eu escreveria:

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

E aquele através do grep oneliner com --perl-regexpopção,

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

Explicação:

(?<=^\")[^"]*-> Um lookbehind é usado aqui. Ele corresponde a qualquer caractere, mas não é igual a "zero ou mais vezes (depois de encontrar aspas duplas, para de corresponder), logo após aspas duplas (apenas a linha que começa com aspas duplas).

Outro truque feio sed,

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

como o regex possui modos ganancioso e não ganancioso, se você tiver vários destinos na mesma linha, ele não será extraído conforme desejado. Linha:

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

Alvo:

tom
jerry

Comando (modo ganancioso):

grep -oP '".*"' name

Comando (modo não ganancioso):

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