¿Cómo extraigo el contenido de las cadenas entre comillas de la salida de un comando?

26

Tengo salida de VBoxManage list vmsque se ve así:

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

Tengo que agarrar los nombres archy arch2y guardarlos en una variable.

Harrys Kavan
fuente

Respuestas:

34

Usando grep + sed

Esto analizará el contenido de esas 2 cadenas:

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

Lo anterior busca una cadena que coincida con el patrón ".*". Eso coincidirá con cualquier cosa que ocurra entre comillas dobles. Entonces grepdevolverá este tipo de valores:

"arch"
"arch2"

La canalización sedeliminará las comillas dobles de estas cadenas para darle las cadenas que está buscando. La notación sed 's/"//g'está instruyendo a sedhacer una búsqueda y reemplazo en todas las apariciones de comillas dobles, sustituyéndolas con nada, s/"//g. El comando s/find/replace/ges lo que está sucediendo allí, y el seguimiento gde la búsqueda le dice que lo haga globalmente en toda la cadena que se le da.

Usando solo sed

También puede usar sedpara cortar la comilla doble inicial, mantener lo que hay entre ellas y cortar la comilla restante + todo lo que está después:

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

Otros metodos

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

El comando trse puede usar para eliminar caracteres. En este caso, se eliminan las comillas dobles.

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

Con grepla función PCRE, puede buscar cualquier subcadena que comience con una comilla doble o termine con una comilla doble e informe solo la subcadena.

slm
fuente
1
tr -d \"Es otra forma de eliminar las comillas. ( trnormalmente traduce un conjunto de caracteres en otro; -dle dice que simplemente los elimine en su lugar).
deltab
1
SLM - si se agrega una /address/al sedigual que sed '/^"\(arch[^"]*\)/s//\1/usted sólo opera en las líneas que contienen esa cadena.
mikeserv
1
@mikeserv: cierto, no estaba seguro de cuán consistente sería el arco en su salida. Pero si es así, entonces eso también funcionaría.
slm
1
buen punto slm. No hay indicios de que sea consistente. Lo siento.
mikeserv
2
Sin embargo, me di cuenta de que sedrealmente debería hacerlo s/^"\([^"]*\)".*/\1/solo en caso de que solo haya dos comillas dobles en la línea.
mikeserv
19

Ese es otro trabajo para cut:

VBoxManage list vms | cut -d \" -f2
Stéphane Chazelas
fuente
3
¡Muy aseado! Cómo funciona: cutdivide cada línea en campos usando la comilla como delimitador, luego genera el campo 2: el campo 1 es la cadena vacía antes de la primera cita, el campo 2 es la cadena deseada entre las comillas y el campo 3 es el resto del línea.
deltab
7

Con sedusted puede hacer:

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

Explicación:

  • s/.../.../ - emparejar y reemplazar
  • ^- partido al inicio de la línea
  • \(...\) - esta es una referencia inversa, podemos referirnos a lo que coincide aquí más adelante con \1
  • [^"]*- coincide con cualquier secuencia que no contenga un "(es decir, hasta el siguiente ")
  • .* - coincide con el resto de la línea
  • \1 - reemplazar con la referencia posterior

O con awk:

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

Tenga en cuenta que en los shells modernos también puede usar una matriz en lugar de una variable normal. En bashpuedes hacer:

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

Esto podría ser más fácil cuando utilizas la variable.

Graeme
fuente
¿Romperías ese comando sed por mí, por favor?
Harrys Kavan
5

Usando bash, escribiría:

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

Y el de grep oneliner con --perl-regexpopción,

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

Explicación:

(?<=^\")[^"]*-> Aquí se usa un lookbehind. Coincide con cualquier carácter pero no "cero o más veces (una vez que encuentra comillas dobles, deja de coincidir) que están justo después de las comillas dobles (solo la línea que comienza con comillas dobles).

Otro truco feo sed,

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

Dado que regex tiene modos codiciosos y no codiciosos, si tiene múltiples objetivos en la misma línea, no se extraerá como desee. Línea:

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

Objetivo:

tom
jerry

Comando (modo codicioso):

grep -oP '".*"' name

Comando (modo no codicioso):

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