Ho trovato alcuni modi per passare variabili di shell esterne a uno script awk
, ma sono confuso su '
"e
"`.
Per prima cosa, ho provato con uno script di shell:
$ v=123test
$ echo $v
123test
$ echo "$v"
123test
Poi ho provato con awk:
$ awk 'BEGIN{print "'$v'"}'
$ 123test
$ awk 'BEGIN{print '"$v"'}'
$ 123
Perché c'è 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.
awk
può essere fatto in diversi modi. Alcuni sono migliori di altri. Questo dovrebbe coprire la maggior parte di essi. Se hai un commento, per favore lascia qui sotto.
-v
(Il modo migliore, il più portabile)Usa l'opzione -v
: (P.S. usa uno spazio dopo -v
o sarà meno portabile. Per esempio, awk -v var=
non 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 dei awk
, e la variabile è disponibile anche nel blocco BEGIN
:
Se hai più variabili:
awk -v a="$var1" -v b="$var2" 'BEGIN {print a,b}'
Attenzione. Come scrive Ed Morton, le sequenze di escape saranno interpretate in modo che \t
diventi un vero tab
e non \t
se è quello che cerchi. Può essere risolto usando ENVIRON[]
o accedendovi tramite ARGV[]
.
PS Se ti piacciono tre barre verticali come separatore ||||
, non può essere evaso, quindi usa -F"[|][|][|]"
Esempio per ottenere dati da un programma/funzione inn a awk
(qui viene usata la data)
awk -v time="$(date +"%F %H:%M" -d '-1 minute')" 'BEGIN {print time}'
Qui otteniamo la variabile dopo il codice awk
. Questo funzionerà bene finché non avrete 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
Questo funziona anche con variabili multiple
awk '{print a,b,$0}' a="$var1" b="$var2" file
Usare la variabile in questo modo non funziona nel blocco BEGIN
:
echo "input data" | awk 'BEGIN {print var}' var="${variable}"
Le variabili possono anche essere aggiunte a awk
usando una here-string dalle shell che le supportano (incluso Bash):
awk '{print $0}' <<< "$variable"
test
Questo è lo stesso di:
printf '%s' "$variable" | awk '{print $0}'
P.S. questo tratta la variabile come un file di input.
Come scrive TrueY, puoi usare ENVIRON
per stampare le variabili ambientali.
Impostando una variabile prima di eseguire AWK, puoi stamparla in questo modo:
X=MyVar
awk 'BEGIN{print ENVIRON["X"],ENVIRON["SHELL"]}'
MyVar /bin/bash
Come scrive Steven Penny, potete usare ARGV
per ottenere i dati in awk:
v="my data"
awk 'BEGIN {print ARGV[1]}' "$v"
my data
Per ottenere i dati nel codice stesso, non solo nel BEGIN:
v="my data"
echo "test" | awk 'BEGIN{var=ARGV[1];ARGV[1]=""} {print var, $0}' "$v"
my data test
Si può usare una variabile all'interno del codice awk
, ma è disordinato e difficile da leggere, e come fa notare Charles Duffy
, questa versione può anche essere vittima di code injection. Se qualcuno aggiunge roba cattiva alla variabile, questa verrà eseguita come parte del codice awk
.
Questo funziona estraendo la variabile all'interno del codice, quindi diventa una parte di esso.
Se volete fare un awk
che cambia dinamicamente con l'uso delle variabili, potete farlo in questo modo, ma NON usatelo 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
Potete aggiungere molti comandi a awk
in questo modo. Anche farlo andare in crash con comandi non validi.
E' sempre bene citare due volte la variabile "$variabile"
.
In caso contrario, le linee multiple saranno aggiunte 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 si possono ottenere senza le doppie virgolette:
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 le virgolette singole, non espande il valore della variabile:
awk -v var='$variable' 'BEGIN {print var}'
$variable
Usa uno di questi a seconda di come vuoi che siano gestiti i backslash nelle variabili di shell (avar
è una variabile awk, svar
è una variabile di shell):
awk -v avar="$svar" '... avar ...' file
awk 'BEGIN{avar=ARGV[1];ARGV[1]=""}... avar ...' "$svar" file
Vedere http://cfajohnson.com/shell/cus-faq-2.html#Q24 per dettagli e altre opzioni. Il primo metodo sopra è quasi sempre la vostra migliore opzione e ha la semantica più ovvia.
Potreste passare l'opzione command-line option -v
con un nome di variabile (v
) e un valore (=
) della variabile d'ambiente ("${v}"
):
% awk -vv="${v}" 'BEGIN { print v }'
123test
O per renderlo più chiaro (con molte meno v
):
% environment_variable=123test
% awk -vawk_variable="${environment_variable}" 'BEGIN { print awk_variable }'
123test