AWK: Passando variáveis ​​​​do shell para o awk

AWK: Passando variáveis ​​​​do shell para o awk

Estou tentando passar umvariávelnúmero de argumentos do shell script para um subconjunto de reconhecimento de padrões 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 subset.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

Também tentei group = "$TOKEN", "group = $TOKEN" e 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!

EDIT: tentei correr

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

sem sucesso... (mesmo erro acima) alguém sabe algum motivo para isso acontecer?

Responder1

Você deve escrever:

-v group="$TOKEN"

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

Responder2

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 deseja considerar os argumentos como expressões regulares 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

Responder3

Seu problema imediato são os espaços ao redor do sinal de igual. O argumento para a -vopção deve ser uma atribuiçã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 arquivo).

Você cometeu um erro semelhante no shell script mais acima: week = $1deveria ser week="$1".

Por falar nisso,sempre coloque aspas duplas nas substituições de comandos. Por exemplo, se TOKENfor *, seria substituído pela lista de arquivos no diretório atual.

awk -v "group=$TOKEN"

Porém, isso não é definido groupcom o valor de TOKEN, porque awk trata o lado direito da atribuição como um literal na sintaxe do awk. Por exemplo, se o valor de TOKENfor a string de 7 caracteres foo\bar, então a variável awk groupserá definida como a string de 6 caracteres foo␈aronde é um caractere de retrocesso (valor de byte 8).

A maneira direta de passar uma variável para um script awk é exportá-la para o ambiente e usá-la por meio do ENVIRONarray.

Além disso, você não está usando a variável groupem nenhum lugar do script awk. A regexp /group/corresponde a qualquer string que contenha a string de 5 caracteres group. Se você quiser verificar se o campo é exatamente o valor de group(de modo que, por exemplo, se o valor de TOKENfor, GROUP2então um campo contendo GROUP24nã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 completo, simplificado um pouco mais para usar a sintaxe de condição-ação do awk (onde a ação é omitida aqui, pois print $0é o padrão) e para evitar abrir o arquivo de saída todas as vezes:

#!/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"

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

informação relacionada