web-dev-qa-db-fra.com

Comment utiliser les variables Shell dans un script awk?

J'ai trouvé des moyens de transmettre des variables Shell externes à un script awk, mais je suis confus à propos de ' et ".

J'ai d'abord essayé avec un script Shell:

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

Puis essayé awk:

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

Pourquoi est la différence?

Enfin j'ai essayé ceci:

$ 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 

Je suis confus à ce sujet.

204
hqjma

Obtenir les variables du shell dans awk

peut être fait de plusieurs manières. Certains sont meilleurs que d'autres. Cela devrait couvrir la plupart d'entre eux. Si vous avez un commentaire, laissez s'il vous plaît ci-dessous.


- Using -v (Le meilleur moyen, le plus portable)

Il utilise l'option -v: (P.S. utilisez un espace après -v ou il sera moins portable. Par exemple, awk -v var= et non pas awk -vvar=)

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

Cela devrait être compatible avec la plupart des awk et la variable est également disponible dans le bloc BEGIN:

Si vous avez plusieurs variables:

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

Attention. Comme l'écrit Ed Morton, les séquences d'échappement seront interprétées de manière à ce que \t devienne un réel tab et non \t si c'est ce que vous recherchez. Peut être résolu en utilisant ENVIRON[] ou y accéder via ARGV[]


- Variable après le bloc de code

Ici, nous obtenons la variable après le code awk. Cela fonctionnera correctement tant que vous n'avez pas besoin de la variable dans le bloc BEGIN:

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

Cela fonctionne également avec plusieurs variables awk '{print a,b,$0}' a="$var1" b="$var2" file

L'utilisation d'une variable de cette manière ne fonctionne pas dans le bloc BEGIN:

echo "input data" | awk 'BEGIN {print var}' var="${variable}"

- Ici string

La variable peut également être ajoutée à awk à l’aide de ici chaîne

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

C'est pareil que:

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

PS, cela menace la variable en tant qu'entrée de fichier


- Entrée ENVIRON

En écriture TrueY, vous pouvez utiliser la variable ENVIRON pour imprimer Environmental Variables Définir une variable avant d'exécuter AWK, vous pouvez l'imprimer comme suit:

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

- entrée ARGV

Comme l'a écrit Steven Penny, vous pouvez utiliser ARGV pour obtenir le Data Inn à awk.

v="my data"
awk 'BEGIN {print ARGV[1]}' "$v"
my data

Pour obtenir le fichier de données au code lui-même et pas seulement au début:

v="my data"
echo "test" | awk 'BEGIN{var=ARGV[1];ARGV[1]=""} {print var, $0}' "$v"
my data test

- Variable dans le code: UTILISER AVEC CAUTION

Vous pouvez utiliser une variable dans le code awk, mais elle est difficile à lire, et comme le souligne Charles Duffy, cette version peut également être victime d'une injection de code. Si quelqu'un ajoute des éléments incorrects à la variable, celle-ci sera exécutée dans le code awk.

Cela fonctionne en extrayant la variable dans le code, de sorte qu’elle en fasse partie.

Si vous voulez créer une awk qui change de façon dynamique avec l'utilisation de variables, vous pouvez le faire de cette façon, ne l'utilisez PAS pour des variables normales.

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

Voici un exemple d'injection de code:

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

Vous pouvez ajouter de nombreuses commandes à awk de cette façon. Même le faire planter avec des commandes non valides.


- Informaitons supplémentaires:

Utilisation de la citation double
Il est toujours bon de doubler la variable "$variable"
Sinon, plusieurs lignes seront ajoutées en une seule ligne longue.

Exemple:

var="Line one
This is line two"

echo $var
Line one This is line two

echo "$var"
Line one
This is line two

Autres erreurs que vous pouvez obtenir sans guillemet double:

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

Et avec un guillemet simple, cela n'augmente pas la valeur de la variable:

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

Plus d'informations sur AWK et les variables
Lire cette FAQ

362
Jotne

Il semble que le bon vieux ENVIRONawk hash intégré ne soit pas du tout mentionné. Un exemple de son utilisation:

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

Utilisez l’un ou l’autre de ces choix en fonction de la manière dont vous souhaitez que les barres obliques inverses soient traitées dans les variables Shell (avar est une variable awk, svar est une variable shell):

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

Voir http://cfajohnson.com/Shell/cus-faq-2.html#Q24 pour plus de détails et d’autres options. La première méthode ci-dessus est presque toujours votre meilleure option et a la sémantique la plus évidente.

8
Ed Morton

Vous pouvez passer l'option de ligne de commande -v avec un nom de variable (v) et une valeur (=) de la variable d'environnement ("${v}"):

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

Ou pour le rendre plus clair (avec beaucoup moins de vs):

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

Vous pouvez utiliser ARGV:

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

Notez que si vous allez continuer dans le corps, vous devrez ajuster ARGC:

awk 'BEGIN {ARGC--} {print ARGV[2], $0}' file "$v"
3
Steven Penny
for i in chr{1..22} chrX chrY
do
awk -v chr="$i" '$1==chr' ../snp150.hg19.txt >> $chr.vcf.bed
echo $i
done
0
Shicheng Guo

Je devais insérer la date au début des lignes d'un fichier journal et c'est comme suit

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

Il peut être redirigé vers un autre fichier pour enregistrer

0
Sina

Je viens de changer la réponse de @ Jotne pour "for loop". 

for i in `seq 11 20`; do Host myserver-$i | awk -v i="$i" '{print "myserver-"i" " $4}'; done
0
edib