risposta-alla-domanda-sullo-sviluppo-web-bd.com

Come posso usare le variabili Shell in uno script awk?

Ho trovato alcuni modi per passare variabili esterne Shell a uno script awk, ma sono confuso su ' e ".

Per prima cosa, ho provato con uno script Shell:

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

Quindi ho provato awk:

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

Perché la differenza?

Infine ho provato questo:

$ 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 

Sono confuso su questo.

204
hqjma

Ottenere le variabili Shell in awk

può essere fatto in diversi modi. Alcuni sono migliori di altri. Questo dovrebbe riguardare la maggior parte di loro. Se hai un commento, per favore, lascia qui sotto.


- Using -v (Il modo migliore, più portatile)

Usa l'opzione -v: (P.S. usa uno spazio dopo -v o sarà meno portabile.E., awk -v var= not awk -vvar=)

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

Questo dovrebbe essere compatibile con la maggior parte di awk e la variabile è disponibile anche nel blocco BEGIN:

Se hai più variabili:

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

Avvertimento. Come scrive Ed Morton, le sequenze di escape verranno interpretate in modo che \t diventi un tab reale e non \t se questo è ciò che si cerca. Può essere risolto utilizzando ENVIRON[] o accedendolo tramite ARGV[]


- Variabile dopo il blocco del codice

Qui otteniamo la variabile dopo il codice awk. Funzionerà bene finché non avrai bisogno della variabile nel blocco BEGIN:

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

Funziona anche con più variabili awk '{print a,b,$0}' a="$var1" b="$var2" file

L'uso della variabile in questo modo non funziona nel blocco BEGIN:

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

- Here string

La variabile può anche essere aggiunta a awk usando here string

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

Questo è lo stesso di:

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

PS, questo minaccia la variabile come input di file


- ENVIRON input

Come TrueY write, puoi usare ENVIRON per stampare Environmental Variables Impostando una variabile prima di eseguire AWK, puoi stamparla in questo modo:

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

- Ingresso ARGV

Come scrive Steven Penny, puoi usare ARGV per fare in modo che la raccolta di dati funzioni.

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

Per ottenere il data inn per il codice stesso non solo l'INIZIO:

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

- Variabile all'interno del codice: USE WITH CAUTION

Puoi usare una variabile all'interno del codice awk, ma è disordinata e difficile da leggere e, come sottolinea Charles Duffy, questa versione potrebbe anche essere vittima dell'iniezione di codice. Se qualcuno aggiunge cose cattive alla variabile, verrà eseguito come parte del codice awk.

Funziona estraendo la variabile all'interno del codice, quindi diventa parte di esso.

Se vuoi creare un awk che cambia dinamicamente con l'uso di variabili, puoi farlo in questo modo, bot NON usarlo per le variabili normali.

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

Ecco un esempio di iniezione di codice:

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

È possibile aggiungere molti comandi a awk in questo modo. Anche farlo schiantare con comandi non validi.


- Ulteriori informazioni:

Uso della doppia citazione
È sempre bene raddoppiare la variabile "$variable"
In caso contrario, verranno aggiunte più righe come una lunga linea singola.

Esempio:

var="Line one
This is line two"

echo $var
Line one This is line two

echo "$var"
Line one
This is line two

Altri errori che puoi ottenere senza virgolette doppie:

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 con virgolette singole, non espande il valore della variabile:

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

Ulteriori informazioni su AWK e variabili
Leggi questa FAQ

362
Jotne

Sembra che il buon vecchio ENVIRONawk hash built-in non sia menzionato affatto. Un esempio del suo utilizzo:

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

Usa una di queste opzioni a seconda di come vuoi gestire i backslash nelle variabili Shell (avar è una variabile awk, svar è una variabile Shell):

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

Vedi http://cfajohnson.com/Shell/cus-faq-2.html#Q24 per dettagli e altre opzioni. Il primo metodo sopra è quasi sempre la tua migliore opzione e ha la semantica più ovvia.

8
Ed Morton

È possibile passare l'opzione command-line-v con un nome di variabile (v) e un valore (=) della variabile di ambiente ("${v}"):

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

O per renderlo più chiaro (con molto meno vs):

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

Puoi utilizzare ARGV:

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

Nota che se hai intenzione di continuare nel corpo, dovrai regolare 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

Ho dovuto inserire la data all'inizio delle righe di un file di registro ed è fatta come di seguito:

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

Può essere reindirizzato a un altro file da salvare

0
Sina

Ho appena cambiato la risposta di @ Jotne per "for loop". 

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