Como usar Awk para imprimir entre dois parâmetros posicionais

2

Existe uma maneira de imprimir tudo depois de um parâmetro posicional usando o awk? O que eu gostaria que o seguinte comando fosse impresso é "p4 p5 p6 p7"

echo p1 p2 p3 p4 p5 p6 p7 | awk '{print $4...}'

Além disso, é possível imprimir entre dois parâmetros posicionais. A seguinte impressão "p4 p5 p6"

echo p1 p2 p3 p4 p5 p6 p7 | awk '{print $4...$6}'

Eu gostaria de evitar o uso de regex e ter que digitar: awk '{print $ 4 "" $ 5 "" $ 6}'

    
por Orando 01.04.2016 / 02:39

3 respostas

1

Se os seus parâmetros forem separados de forma confiável por exatamente um espaço cada, você poderá usar cut da seguinte forma:

echo p1 p2 p3 p4 p5 p6 p7 | cut -d' ' -f4-   # For p4 onwards
echo p1 p2 p3 p4 p5 p6 p7 | cut -d' ' -f4-6  # For p4 to p6

Se você quiser parâmetros separados por espaços em branco, a maneira como awk os analisa, de maneira confiável, fica mais complicada. Para um exemplo do que estou falando e como o acima pode nem sempre fazer o que você quer, tente:

printf '%s   ' p1 p2 p3 p4 p5 p6 p7 | cut -d' ' -f4-
printf '%s   ' p1 p2 p3 p4 p5 p6 p7 | cut -d' ' -f4-6

Você pode ver que cut está tratando cada espaço como um delimitador, em vez de qualquer sequência de espaços consecutivos como um delimitador da maneira que awk faz. Você pode forçar o awk a fazer o que quiser com um loop:

echo p1 p2 p3 p4 p5 p6 p7 | awk '{for (a=4;a<=NF;a++) {printf "%s ", $a} printf "\n"}'

No entanto, isso deixa um espaço à direita no final da linha. Isso pode ser resolvido, mas fica mais confuso e confuso. Dependendo dos seus requisitos, o comando cut pode estar bem.

    
por 01.04.2016 / 03:28
1

awk não pode fazer isso (sem usar um loop de algum tipo), mas perl pode.

Lembre-se, no entanto, que perl matrizes são baseadas em zero (enquanto awk índices de matriz começam em 1).

Por exemplo, usando a opção perl -a para divisão automática semelhante a awk :

$ echo p1 p2 p3 p4 p5 p6 p7 | perl -ane 'print "@F[3..$#F]\n";'
p4 p5 p6 p7 

$ echo p1 p2 p3 p4 p5 p6 p7 | perl -ane 'print "@F[2,4,6]\n";'
p3 p5 p7

$ echo p1 p2 p3 p4 p5 p6 p7 | perl -ane 'print "@F[1..3]\n";'
p2 p3 p4

veja man perldata ou perldoc perlvar para mais informações sobre arrays e fatias de array.

Como as fatias da matriz estão sendo impressas em uma sequência de aspas duplas, ele usa o valor de $" aka $LIST_SEPARATOR para separar os elementos da matriz. Se eles fossem impressos / usados fora de uma string com aspas duplas, não haveria nenhum separador entre os elementos. Veja man perlvar ou perldoc perlvar e procure por LIST_SEPARATOR.

Por fim, não use perl -a se o delimitador de campo não tiver nada além de espaço em branco ( \s+ em PCRE). Divida você mesmo assim:

$ echo "p1:p2:p3:p4:p5:p6:p7" | perl -n -e '@F=split /:/; print "@F[0..4]\n";'
p1 p2 p3 p4 p5
    
por 02.04.2016 / 00:27
0

Aqui está uma maneira de fazer isso usando a função split do awk (por resposta anterior, requer um loop for):

Descrição:

 "sub_0"         - variable to contain desired output ($0 substring)

 "beg"           - 1st desired field (references 4th element in "pn_ary" array)
                   (external "$beg" shell variable passed into awk (internal "beg" variable)

 "end"           - # of fields in $0 (split function loads each field in $0 as a "pn_ary[n]" element ("1-n"))

 "split(s,a,sep) - "s": string, "a": array, "sep": seperator (splits "s" per "sep", loads "a")
                   ("split" returns # of elements loaded into "pn_ary" array into "end" variable)

 "FS"            - awk system Field Seperator variable

 "[:graph:]"     - Posix bracket expression for visible ASCII chars in range "[\x21-\x7E]"   

Sintaxe:

 beg="4"

 echo "p1 p2 p3 p4 p5 p6 p7" |\

 awk '{sub_0="";end=split($0,pn_ary,FS)
       for (i=beg;i<=end;i++) {sub_0=sub_0""FS""pn_ary[i]}     
       print substr(sub_0,match(sub_0,"[:graph:]"))
      }' beg="$beg"

Saída:

p4 p5 p6 p7

    
por 27.01.2017 / 22:27

Tags