Use uma variável shell no awk

8

Aqui está o meu script (para encontrar os arquivos que contêm um padrão especificado):

find . -type f \
    -exec awk -v vawk="$1" '/'"$vawk"'/ {c++} c>0 { print ARGV[1]; exit 0 } END { if (! c) {exit 1}}' \{\} \;

Eu gostaria de usar meu script com um argumento §:

MyScript.sh pattern

Meu problema é que eu não conseguem colocar a $1variável awk.

Quando tento depurar meu script

bash -x MyScript.sh pattern

Aqui está a saída:

+ find . -type f -exec awk -v vawk=pattern '// {c++} c>0 {print ARGV[1] ; exit 0 } END { if (! c) {exit 1}}' '{}' ';'

A $vawkvariável parece estar vazia.

Qualquer ideia?

Nicolas
fonte

Respostas:

7

Você parece estar confundindo variáveis ​​awk e shell. awk -v vawk="$1"cria uma variável awk chamada vawk, mas você está tentando usar a sintaxe do shell ( $vawk). Isso não funciona porque o shell não tem uma variável chamada vawk. Eu acho que o que você quer é

awk -v vawk="$1" '$0 ~ vawk { c++ } # ...'
#                      ^ awk variable syntax
jw013
fonte
1
Observe que awkexpande as seqüências de escape do tipo C $1para que a abordagem não funcione se $1puder conter caracteres de barra invertida (comum para regexps). Você pode usar a ENVIRONmatriz especial awk.
Stéphane Chazelas
6

Reproduzido a partir disso, agora encerrado como pergunta duplicada , pois inclui avisos sobre as limitações da passagem de variável do awk que podem ser úteis.

Uma variável shell é apenas isso: uma variável shell . Se você quiser transformá-lo em uma variável awk , precisará de uma sintaxe como:

awk -v x="$x" '$2 == x {print $1}' infile

ou

awk '$2 == x {print $1}' x="$x" infile

No entanto, eles sofrem de um problema: as seqüências de escape são expandidas nelas (e com o GNU awk4.2 ou superior, se $xcomeça @/e termina /, é tratado como uma variável do tipo regexp ).

Portanto, por exemplo, se a variável shell contiver os dois caracteres barra in e n , a variável awk acabará contendo o caractere de nova linha (e com gawk 4.2+, se contiver @/foo/, a variável awk conterá fooe será do tipo regexp).

Outra abordagem (mas que like for -vrequer um POSIX awk ou nawk (em oposição ao awk dos anos 70 ainda encontrado /bin/awkno Solaris)) é usar variáveis ​​de ambiente:

x="$x" awk '$2 == ENVIRON["x"] {print $1}' infile

Outra abordagem (ainda com awks mais recentes) é usar a matriz ARGV no awk:

awk 'BEGIN {x = ARGV[1]; delete ARGV[1]}
  $2 == x {print $1}' "$x" infile
Stéphane Chazelas
fonte