Usa una variabile di shell in awk


8

Ecco il mio script (per trovare i file che contengono uno schema specificato):

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

Vorrei usare la mia sceneggiatura con un argomento §:

MyScript.sh pattern

Il mio problema è che non riesco a inserire la $1variabile awk.

Quando provo a eseguire il debug del mio script

bash -x MyScript.sh pattern

Ecco l'output:

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

La $vawkvariabile sembra essere vuota.

Qualche idea?

Risposte:


7

Sembra che tu confonda le variabili awk e le variabili shell. awk -v vawk="$1"crea una variabile awk chiamata vawk, ma stai provando a usare la sintassi della shell ( $vawk). Questo non funziona perché la shell non ha una variabile chiamata vawk. Penso che quello che vuoi sia

awk -v vawk="$1" '$0 ~ vawk { c++ } # ...'
#                      ^ awk variable syntax

1
Si noti che awkespande le sequenze di escape simili a C in $1, quindi l'approccio non funziona se $1può contenere caratteri di barra rovesciata (comune per regexps). In ENVIRONalternativa, è possibile utilizzare l' array speciale awk.
Stéphane Chazelas,

6

Riprodotto da questo ora chiuso come domanda duplicata in quanto include avvisi sui limiti del passaggio della variabile awk che si potrebbero trovare utili.

Una variabile di shell è proprio questa: una variabile di shell . Se vuoi trasformarlo in una variabile awk , hai bisogno di una sintassi come:

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

o

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

Tuttavia, quelli soffrono di un problema: le sequenze di escape sono espanse in esse (e con GNU awk4.2 o versioni successive, se $xinizia @/e finisce in /, viene trattata come una variabile regexp ).

Quindi, per esempio se la variabile shell contiene i due caratteri barra rovesciata e n , la variabile awk finirà per contenere il carattere newline (e con gawk 4.2+, se contiene @/foo/, la variabile awk conterrà fooe sarà di tipo regexp).

Un altro approccio (ma che -vrichiede un POSIX awk o nawk (al contrario del awk degli anni '70 ancora trovato come /bin/awkin Solaris)) è usare le variabili d'ambiente:

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

Un altro approccio (sempre con awk più recenti) è quello di utilizzare l'array ARGV in awk:

awk 'BEGIN {x = ARGV[1]; delete ARGV[1]}
  $2 == x {print $1}' "$x" infile
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.