Use una variable de shell en awk

8

Aquí está mi script (para encontrar los archivos que contienen un patrón específico):

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

Me gustaría usar mi script con un argumento §:

MyScript.sh pattern

Mi problema es que no logro poner la $1variable awk.

Cuando intento depurar mi script

bash -x MyScript.sh pattern

Aquí está la salida:

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

La $vawkvariable parece estar vacía.

¿Alguna idea?

Nicolas
fuente

Respuestas:

7

Parece confundir las variables awk y las variables de shell. awk -v vawk="$1"crea una variable awk llamada vawk, pero está intentando utilizar la sintaxis de shell ( $vawk). Esto no funciona porque el shell no tiene una variable llamada vawk. Creo que lo que quieres es

awk -v vawk="$1" '$0 ~ vawk { c++ } # ...'
#                      ^ awk variable syntax
jw013
fuente
1
Tenga en cuenta que awkexpande las secuencias de escape tipo C $1, por lo que ese enfoque no funciona si $1puede contener caracteres de barra invertida (común para expresiones regulares). Puede utilizar la ENVIRONmatriz especial awk en su lugar.
Stéphane Chazelas
6

Reproducido de esto ahora cerrado como una pregunta duplicada , ya que incluye advertencias sobre las limitaciones del paso de variable awk que uno podría encontrar útil.

Una variable de shell es solo eso: una variable de shell . Si desea convertirlo en una variable awk , necesita una sintaxis como:

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

o

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

Sin embargo, esos sufren un problema: las secuencias de escape se expanden en ellos (y con GNU awk4.2 o superior, si $xcomienza @/y termina en /, se trata como un tipo de variable regexp ).

Así, por ejemplo, si la variable de shell contiene los dos caracteres de barra invertida y n , la variable awk terminarán que contiene la nueva línea de caracteres (y con gawk 4.2+, si contiene @/foo/, la variable awk contendrá fooy ser de tipo regexp).

Otro enfoque (pero que -vrequiere un POSIX awk o nawk (a diferencia del awk de 1970 que todavía se encuentra como /bin/awken Solaris)) es utilizar variables de entorno:

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

Otro enfoque (todavía con awks más nuevos) es usar la matriz ARGV en awk:

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