Linha de Comandos: Extrair substring da saída

25

Digamos que eu execute o comando SayStuff

$ SayStuff

e a saída é

Watermelons and cucumbers

Agora. Digamos que eu queira extrair a substring cucumbersda saída e canalizá-la em algo.
A maneira como eu faria isso programaticamente seria dividir a saída em uma matriz pelo delimitador Space e referenciá-la ArrayName[2]. Sou bastante novo no shell scripts e só consegui descobrir cutexemplos semi-criptográficos , nenhum dos quais fazia sentido.

Alguma ideia?

Krystah
fonte

Respostas:

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

O -d ' 'diz cutpara dividir em espaços. -f 3seleciona a terceira coluna.

Você também pode usar awk, que faz a divisão com base no espaço e já faz as colunas disponíveis como $1, $2...

$ echo "Watermelons and cucumbers" | awk '{ print $3 }'
cucumbers
slhck
fonte
Observe que cutnão manipulará um número variável de espaços, enquanto o awkfaz.
Zitrax
13

Eu provavelmente usaria uma das opções já fornecidas pelo @slhck, mas aqui estão mais algumas maneiras de fazer isso:

  1. Usando matrizes, como faria em qualquer outro idioma:

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

    O var=()declara uma matriz, $(command)salva a saída do comando. Então, foo=( $(SayStuff) )armazena a saída de SayStuffdentro da matriz fooe você echoé o terceiro elemento ${foo[2]}.

  2. sed

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

    O sedcomando substituirá ( s///) tudo pela última palavra. A regex corresponde a qualquer espaço ( .*) que corresponda a tudo até o último espaço e, em seguida, captura a última palavra (\(.*\). Como a palavra foi capturada, podemos nos referir a ela como \1.

    Uma versão mais simples:

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

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

    Isso usa as habilidades de manipulação de string do bash, veja aqui para mais detalhes.

  4. Mais festança

    $ SayStuff | while read a b c; do echo $c; done
    cucumbers
  5. Perl, onde é claro, existem muitas maneiras de fazer isso:

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

    As -amarcas perlse comportam como awk, dividindo linhas no espaço em branco e salvando na matriz @F. Em seguida, imprimimos o último elemento de @F( $#Fé o número de elementos em @F). O comando -ldiz ao perl para adicionar uma nova linha a cada printinstrução, a de -nque ele deve processar STDIN linha por linha e de -eexecutar o script fornecido na linha de comando.

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

    As opções foram explicadas acima, estamos apenas excluindo tudo até o último espaço e impressão ( -p).

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

    Aqui estamos passando Watermelons and cucumberscomo argumentos, que perl salvará na @ARGmatriz e, portanto, imprimimos o último elemento de @ARG.

  6. truques. Este usa sedpara converter espaços em novas linhas e, em seguida, tailimprimir apenas a última linha.

    $ SayStuff | sed 's/ /\n/g' | tail -n 1
    cucumbers
  7. expressões regulares e grep, usando as -oquais imprime apenas a sequência correspondente.

    $ SayStuff | grep -Po '\w+$' 
    cucumbers
  8. traindo

    $ SayStuff | grep -o cucumbers
    cucumbers
Terdon
fonte
2

Aqui está mais uma explicação:

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

Então, se você precisar do terceiro campo e ele estiver delimitado por espaços '', será

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

Se você deseja o último campo, provavelmente deve usar o awk .
Nesse caso, torna-se:

$ echo "Melancias e pepinos" |
pepinos awk '{print $ NF}'

Em awkNF é o número de campos na linha, então $NFsignifica o último campo na linha.

zeridon
fonte
basicamente a mesma pergunta é aqui, mas mais generalizada: stackoverflow.com/questions/3162385/... Sim, você pode usar outras maneiras, mas awk é o mais curto
zeridon