¿Cómo uso las variables de shell en un script awk?

Encontré algunas maneras de pasar variables de shell externas a un script awk , pero estoy confundido acerca de ' y " .

Primero, lo intenté con un script de shell:

 $ v=123test $ echo $v 123test $ echo "$v" 123test 

Luego intenté awk:

 $ awk 'BEGIN{print "'$v'"}' $ 123test $ awk 'BEGIN{print '"$v"'}' $ 123 

¿Por qué es la diferencia?

Por último, probé esto:

 $ awk 'BEGIN{print " '$v' "}' $ 123test $ awk 'BEGIN{print ' "$v" '}' awk: cmd. line:1: BEGIN{print awk: cmd. line:1: ^ unexpected newline or end of string 

Estoy confundido acerca de esto.

Obtener variables de shell en awk se puede hacer de varias maneras. Algunos son mejores que otros.


Esta es la mejor manera de hacerlo. Utiliza la opción -v : (PS usa un espacio después de -v o será menos portátil. Por ejemplo, awk -v var= not awk -vvar= )

 variable="line one\nline two" awk -v var="$variable" 'BEGIN {print var}' line one line two 

Esto debería ser compatible con la mayoría de awk y la variable también está disponible en el bloque BEGIN :

Múltiples variables

 awk -va="$var1" -vb="$var2" 'BEGIN {print a,b}' 

Aquí obtenemos la variable después del código awk . Esto funcionará bien siempre que no necesite la variable en el bloque BEGIN :

 variable="line one\nline two" echo "input data" | awk '{print var}' var="$variable" or awk '{print var}' var="$variable" file 

Esto también funciona con múltiples variables awk '{print a,b,$0}' a="$var1" b="$var2" file


La variable también se puede agregar a awk usando aquí la cadena

 awk '{print $0}' < << "$variable" test 

Esto es lo mismo que:

 echo "$variable" | awk '{print $0}' 

PD, esto amenaza la variable como una entrada de archivo


Como TrueY write, puede usar ENVIRON para imprimir Environmental Variables Configurando una variable antes de ejecutar AWK, puede imprimirlo así:

 X=MyVar awk 'BEGIN{print ENVIRON["X"],ENVIRON["SHELL"]}' MyVar /bin/bash 

Editar: como escribe "ese otro tipo", esto no maneja la barra diagonal inversa. No recomendado.


Puede usar una variable dentro del código awk , pero es complicado y difícil de leer, y como señala Charles Duffy , esta versión también puede ser una víctima de la inyección de código. Si alguien agrega cosas malas a la variable, se ejecutará como parte del código awk .

Si quiere hacer un awk que cambie dinámicamente con el uso de variables, puede hacerlo de esta manera, bot NO lo use para variables normales.

 variable="line one\nline two" awk 'BEGIN {print "'"$variable"'"}' line one line two 

Aquí hay un ejemplo de inyección de código:

 variable='line one\nline two" ; for (i=1;i< =1000;++i) print i"' awk 'BEGIN {print "'"$variable"'"}' line one line two 1 2 3 . . 1000 

Puede agregar muchos comandos para awk esta manera. Incluso hágalo fallar con comandos no válidos.


Siempre es bueno duplicar la variable de cotización "$variable"
De lo contrario, se agregarán varias líneas como una sola línea larga.

Ejemplo:

 var="Line one This is line two" echo $var Line one This is line two echo "$var" Line one This is line two 

Otros errores que puede obtener sin comillas dobles:

 variable="line one\nline two" awk -v var=$variable 'BEGIN {print var}' awk: cmd. line:1: one\nline awk: cmd. line:1: ^ backslash not last character on line awk: cmd. line:1: one\nline awk: cmd. line:1: ^ syntax error 

Y con comillas simples, no expande el valor de la variable:

 awk -v var='$variable' 'BEGIN {print var}' $variable 

Parece que el viejo hash incorporado ENVIRON awk no se menciona en absoluto. Un ejemplo de su uso:

 $ X=Solaris awk 'BEGIN{print ENVIRON["X"], ENVIRON["TERM"]}' Solaris rxvt 

Utilice cualquiera de estos dependiendo de cómo quiera las barras diagonales inversas en las variables de shell manejadas ( avar es una variable awk, svar es una variable de shell):

 awk -v avar="$svar" '... avar ...' file awk 'BEGIN{avar=ARGV[1];ARGV[1]=""}... avar ...' "$svar" file 

Consulte http://cfajohnson.com/shell/cus-faq-2.html#Q24 para obtener detalles y otras opciones. El primer método anterior es casi siempre su mejor opción y tiene la semántica más obvia.

Podría pasar la opción de línea de comandos -v con un nombre de variable ( v ) y un valor ( = ) de la variable de entorno ( "${v}" ):

 % awk -vv="${v}" 'BEGIN { print v }' 123test 

O para hacerlo más claro (con mucho menos v s):

 % environment_variable=123test % awk -vawk_variable="${environment_variable}" 'BEGIN { print awk_variable }' 123test 

Puede utilizar ARGV:

 v=123test awk 'BEGIN {print ARGV[1]}' "$v" 

Tenga en cuenta que si va a continuar en el cuerpo, deberá ajustar ARGC:

 awk 'BEGIN {ARGC--} {print ARGV[2], $0}' file "$v" 

Tuve que insertar la fecha al comienzo de las líneas de un archivo de registro y se hace como a continuación:

 DATE=$(date +"%Y-%m-%d") awk '{ print "'"$DATE"'", $0; }' /path_to_log_file/log_file.log 

Se puede redirigir a otro archivo para guardar

Acabo de cambiar la respuesta de @ Jotne por “for loop”.

 for i in `seq 11 20`; do host myserver-$i | awk -vi="$i" '{print "myserver-"i" " $4}'; done 
 for i in chr{1..22} chrX chrY do awk -v chr="$i" '$1==chr' ../snp150.hg19.txt >> $chr.vcf.bed echo $i done