Línea de comando: extraer subcadena de salida

25

Digamos que ejecuto el comando SayStuff

$ SayStuff

y la salida es

Watermelons and cucumbers

Ahora. Digamos que quiero extraer la subcadena cucumbersde la salida y canalizarla en algo.
La forma en que haría esto programáticamente sería dividir la salida en una matriz por el delimitador Space y hacer referencia a ella ArrayName[2]. Soy bastante nuevo en los scripts de shell y solo he logrado desenterrar cutejemplos semicrípticos , ninguno de los cuales tenía sentido.

¿Algunas ideas?

krystah
fuente

Respuestas:

30
$ echo "Watermelons and cucumbers" | cut -d ' ' -f 3
cucumbers

Le -d ' 'dice cuta dividir en espacios. -f 3selecciona la tercera columna.

También se puede utilizar awk, lo que hace la división basada en el espacio ya y hace que las columnas disponibles como $1, $2...

$ echo "Watermelons and cucumbers" | awk '{ print $3 }'
cucumbers
slhck
fuente
Tenga en cuenta que cutno manejará un número variable de espacios, mientras que lo awkhará.
Zitrax
13

Probablemente usaría una de las opciones que ya ofrece @slhck, pero aquí hay algunas formas más de hacerlo:

  1. Usando matrices, como lo haría en cualquier otro idioma:

    $ foo=( $(SayStuff) ) 
    $ echo ${foo[2]}
    cucumbers

    El var=()declara una matriz, $(command)guarda la salida del comando. Por lo tanto, foo=( $(SayStuff) )almacena la salida de SayStuffen la matriz fooy luego echoes su tercer elemento con ${foo[2]}.

  2. sed

    $ SayStuff | sed 's/.* \(.*\)/\1/'
    cucumbers

    El sedcomando sustituirá ( s///) todo con la última palabra. La expresión regular coincide con cualquier cosa hasta un espacio ( .*) que coincidirá con todo hasta el último espacio y luego captura la última palabra (\(.*\). Como la palabra ha sido capturada, podemos referirnos a ella como \1.

    Una versión más simple:

    $ SayStuff | sed 's/.* //'
    cucumbers
  3. golpetazo

    $ foo=$(SayStuff); echo ${foo##* } 
    cucumbers

    Esto usa las habilidades de manipulación de cadenas de bash, vea aquí para más detalles.

  4. Más bash

    $ SayStuff | while read a b c; do echo $c; done
    cucumbers
  5. Perl, donde, por supuesto, hay muchas maneras de hacer esto:

    $ SayStuff | perl -lane 'print $F[$#F]'
    cucumber

    Las -amarcas se perlcomportan como awk, dividiendo líneas en espacios en blanco y guardando en la matriz @F. Luego imprimimos el último elemento de @F( $#Fes el número de elementos en @F). El -lle dice a Perl que agregue una nueva línea a cada printinstrucción, -nque debe procesar STDIN línea por línea y -eque debe ejecutar el script dado en la línea de comando.

    $ SayStuff | perl -pe 's/.* //'
    cucumber

    Las opciones se explicaron anteriormente, simplemente estamos eliminando todo hasta el último espacio e imprimiendo ( -p).

    $ perl -le 'print $ARGV[$#ARGV]' $(SayStuff)
    cucumbers

    Aquí estamos pasando Watermelons and cucumberscomo argumentos, que Perl guardará en la @ARGmatriz y, por lo tanto, imprimimos el último elemento de @ARG.

  6. astucia. Este se usa sedpara convertir espacios en nuevas líneas y luego tailpara imprimir solo la última línea.

    $ SayStuff | sed 's/ /\n/g' | tail -n 1
    cucumbers
  7. grep y expresiones regulares, con las -ocuales imprime solo la cadena coincidente.

    $ SayStuff | grep -Po '\w+$' 
    cucumbers
  8. engañando

    $ SayStuff | grep -o cucumbers
    cucumbers
terdon
fuente
2

Aquí hay alguna explicación más:

Usage: cut OPTION... [FILE]...

Print selected parts of lines from each FILE to standard output.

   -d, --delimiter=DELIM
          use DELIM instead of TAB for field delimiter

   -f, --fields=LIST
          select only these fields;  also print any line that contains  no
          delimiter character, unless the -s option is specified

Entonces, si necesita el tercer campo y está delimitado por espacios '', entonces es

$ echo "Watermelons and cucumbers" | cut -d ' ' -f 3  
cucumbers

Si desea el campo ÚLTIMO , probablemente debería usar awk .
En este caso se convierte en:

$ echo "Sandías y pepinos" | awk '{print $ NF}'
pepinos

En awkNF es el número de campos en la línea, por lo que $NFsignifica el último campo en la línea.

zeridon
fuente
básicamente la misma pregunta está aquí pero más generalizada: stackoverflow.com/questions/3162385/… Sí, puedes usar otras formas, pero awk es el más corto
zeridon