AWK: Passando Variáveis do Shell para o awk

3

Estou tentando passar um número variável de argumentos do shell script para um subconjunto de reconhecimento de padrão de uma tabela. Aqui está minha tentativa até agora:

O arquivo 'infile':

    ID,GROUP
    1,GROUP2    
    2,GROUP2    
    3,GROUP4    
    4,GROUP4    
    5,GROUP5    
    6,GROUP5    
    7,GROUP23   
    8,GROUP23   
    9,GROUP23   

O arquivo subconjunto.sh:

    #!/bin/sh
    rm -f outfile_$week

    week = $1
    shift

    for TOKEN in "$@"
    do

    echo "adding records for" $TOKEN

    awk -F "," -v group = $TOKEN '{ if(FNR > 2 && $2 ~/group/){print $0} }' infile >> outfile_$week
    done

Eu também tentei group="$ TOKEN", "group = $ TOKEN" e depois ambos com aspas simples. Estou enviando assim:

    sh subset.sh 061314 GROUP2 GROUP23

O erro que recebo é surpreendentemente pouco informativo

    Usage: awk [-F fs][-v Assignment][-f Progfile|Program][Assignment|File] ...

Qualquer ajuda é muito apreciada, obrigado!

EDITAR: Eu tentei correr

    awk -F "," -v group ="GROUP1" '{ if(FNR > 2 && $2 ~/group/){print $0} }' infile

sem sucesso ... (mesmo erro acima) alguém sabe de alguma razão que isso possa acontecer?

    
por mlegge 13.06.2014 / 20:15

3 respostas

2

Parece que você quer:

awk -F, '
  BEGIN {
    for (i = 1; i < ARGC; i++) group[ARGV[i]]
    ARGC=0
  }
  NR >= 2 && $2 in group' "$@" < infile

Ou se você realmente quiser considerar os argumentos como regexps para corresponder à segunda coluna:

awk -F, '
  BEGIN {
    for (i = 1; i < ARGC; i++) group[ARGV[i]]
    ARGC=0
  }
  NR >= 2 {
    for (i in group) if ($2 ~ i) {print; next}
  }' "$@" < infile
    
por 13.06.2014 / 22:00
4

Você deve escrever:

-v group="$TOKEN"

em vez de -v group = $TOKEN , que causa erro de sintaxe em awk .

    
por 13.06.2014 / 20:32
2

Seu problema imediato é os espaços ao redor do sinal de igual. O argumento para a opção -v deve ser uma atribuição. O Awk vê um argumento para -v , seguido por um script ( = ), seguido por nomes de arquivos (o valor de TOKEN , seu script e seus nomes de arquivos).

Você fez um erro semelhante no script de shell mais acima: week = $1 deve ser week="$1" .

A propósito, sempre coloque aspas duplas em torno das substituições de comandos . Por exemplo, se TOKEN for * , ela será substituída pela lista de arquivos no diretório atual.

awk -v "group=$TOKEN"

Isso não define group como o valor de TOKEN , porque o awk trata o lado direito da atribuição como um literal na sintaxe do awk. Por exemplo, se o valor de TOKEN for a string de 7 caracteres foo\bar , a variável awk group será definida como a string de 6 caracteres foo␈ar , em que é um caractere de retrocesso (valor de byte 8 ).

A maneira direta de passar uma variável para um script awk é exportá-lo para o ambiente e usá-lo via array ENVIRON .

Além disso, você não está usando a variável group em qualquer parte do script awk. O regexp /group/ corresponde a qualquer string contendo a string de 5 caracteres group . Se você quiser verificar se o campo é exatamente o valor de group (para que, por exemplo, se o valor de TOKEN for GROUP2 , um campo contendo GROUP24 não será correspondido), use o operador de igualdade == .

  export TOKEN
  awk -F "," '{ if (FNR > 2 && $2 == ENVIRON["TOKEN"]){print $0} }' infile >> outfile_$week

Aqui está o script inteiro, simplificado um pouco mais para usar a sintaxe de ação-condição do awk (onde a ação é omitida aqui, pois print $0 é o padrão) e para evitar abrir o arquivo de saída toda vez:

#!/bin/sh
week="$1"
shift
for TOKEN in "$@"
do
  echo "adding records for" $TOKEN
  awk -F "," 'FNR > 2 && $2 == ENVIRON["TOKEN"]' infile 
done >"outfile_$week"

Veja a resposta de Stéphane Chazelas para uma maneira mais avançada de usar o awk que não requer o processamento do arquivo de entrada várias vezes .

    
por 15.06.2014 / 23:25