Como eu uso variables ​​shell em um script awk?

Eu encontrei algumas maneiras de passar variables ​​de shell externas para um script awk , mas estou confuso sobre ' e " .

Primeiro, tentei com um script de shell:

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

Então tentei o awk:

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

Por que a diferença?

Por fim, tentei isso:

 $ 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 

Estou confuso sobre isso.

Colocar as variables ​​do shell no awk pode ser feito de várias maneiras. Alguns são melhores que outros.


Essa é a melhor maneira de fazer isso. Ele usa a opção -v : (PS usa um espaço após -v ou será menos portátil. Por exemplo, awk -v var= não awk -vvar= )

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

Isso deve ser compatível com a maioria dos awk e variável está disponível no bloco BEGIN também:

Múltiplas variables

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

Aqui nós pegamos a variável após o código awk . Isso funcionará bem, desde que você não precise da variável no bloco BEGIN :

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

Isto também funciona com múltiplas variables awk '{print a,b,$0}' a="$var1" b="$var2" file


Variável também pode ser adicionada ao awk usando aqui string

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

Isso é o mesmo que:

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

PS, isso ameaça a variável como uma input de arquivo


Como TrueY escreve, você pode usar o ENVIRON para imprimir Environmental Variables Definir uma variável antes de executar o AWK, você pode imprimi-lo assim:

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

Edit: Como "esse outro cara" escrever, isso não suporta backslash. Não recomendado.


Você pode usar uma variável dentro do código awk , mas é confuso e difícil de ler, e como Charles Duffy aponta, esta versão também pode ser uma vítima de injeção de código. Se alguém adicionar coisas ruins à variável, ela será executada como parte do código awk .

Se você quer fazer um awk que muda dinamicamente com o uso de variables, você pode fazer desta forma, bot não o use para variables ​​normais.

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

Aqui está um exemplo de injeção 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 

Você pode adicionar muitos comandos para awk desta maneira. Até mesmo fazê-lo falhar com comandos não válidos.


É sempre bom duplicar a variável "$variable"
Caso contrário, várias linhas serão adicionadas como uma única linha longa.

Exemplo:

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

Outros erros que você pode obter sem aspas duplas:

 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 

E com aspas simples, não expande o valor da variável:

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

Parece que o bom e velho hash embutido ENVIRON não é mencionado. Um exemplo de seu uso:

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

Use um destes dependendo de como você quer barras invertidas nas variables ​​de shell manipuladas ( avar é uma variável awk, svar é uma variável shell):

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

Veja http://cfajohnson.com/shell/cus-faq-2.html#Q24 para detalhes e outras opções. O primeiro método acima é quase sempre sua melhor opção e tem a semântica mais óbvia.

Você poderia passar a opção de linha de comando -v com um nome de variável ( v ) e um valor ( = ) da variável de ambiente ( "${v}" ):

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

Ou para tornar mais claro (com muito menos v s):

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

Você pode utilizar o ARGV:

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

Note que se você for continuar no corpo, precisará ajustar o ARGC:

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

Eu tive que inserir data no início das linhas de um arquivo de log e é feito como abaixo:

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

Pode ser redirecionado para outro arquivo para salvar

Acabei de mudar a resposta da @Jotne para “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