
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 -v
opçã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 = $1
deveria ser week="$1"
.
Por falar nisso,sempre coloque aspas duplas nas substituições de comandos. Por exemplo, se TOKEN
for *
, seria substituído pela lista de arquivos no diretório atual.
awk -v "group=$TOKEN"
Porém, isso não é definido group
com 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 TOKEN
for a string de 7 caracteres foo\bar
, então a variável awk group
será definida como a string de 6 caracteres foo␈ar
onde ␈
é 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 ENVIRON
array.
Além disso, você não está usando a variável group
em 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 TOKEN
for, GROUP2
então 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 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.