Jeg fant noen måter å sende eksterne shell-variabler til et awk
-skript, men jeg er forvirret over '
og &"
.
Først prøvde jeg med et skallskript:
$ v=123test
$ echo $v
123test
$ echo "$v"
123test
Så prøvde jeg awk:
$ awk 'BEGIN{print "'$v'"}'
$ 123test
$ awk 'BEGIN{print '"$v"'}'
$ 123
Hva er forskjellen?
Til slutt prøvde jeg dette:
$ 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
Jeg er forvirret over dette.
Å få shell-variabler inn i
awk
kan gjøres på flere måter. Noen er bedre enn andre. Dette bør dekke de fleste av dem. Hvis du har en kommentar, vennligst legg igjen nedenfor.
-v
(Den beste måten, mest portabel)Bruk -v
-alternativet: (P.S. bruk et mellomrom etter -v
, ellers blir det mindre portabelt. F.eks. awk -v var=
ikke awk -vvar=
).
variable="line one\nline two"
awk -v var="$variable" 'BEGIN {print var}'
line one
line two
Dette bør være kompatibelt med de fleste awk
, og variabelen er også tilgjengelig i BEGIN
-blokken:
Hvis du har flere variabler:
awk -v a="$var1" -v b="$var2" 'BEGIN {print a,b}'
Advarsel. Som Ed Morton skriver, vil escape-sekvenser tolkes slik at \t
blir en ekte tab
og ikke \t
hvis det er det du søker etter. Kan løses ved å bruke ENVIRON[]
eller få tilgang via ARGV[]
.
PS Hvis du liker tre vertikale streker som separator |||
, kan det ikke unngås, så bruk -F "[|][|][|]"
Eksempel på å få data fra et program/funksjon inn til
awk
(her brukes dato)
awk -v time="$(date +"%F %H:%M" -d '-1 minute')" 'BEGIN {print time}'
Her får vi variabelen etter awk
-koden. Dette vil fungere fint så lenge du ikke trenger variabelen i BEGIN
-blokken:
variable="line one\nline two"
echo "input data" | awk '{print var}' var="${variable}"
or
awk '{print var}' var="${variable}" file
Dette fungerer også med flere variabler
awk '{print a,b,$0}' a="$var1" b="$var2" fil
Bruk av variabel på denne måten fungerer ikke i BEGIN
-blokken:
echo "input data" | awk 'BEGIN {print var}' var="${variable}"
Variabler kan også legges til awk
ved hjelp av en here-string fra skall som støtter dem (inkludert Bash):
awk '{print $0}' <<< "$variable"
test
Dette er det samme som:
printf '%s' "$variable" | awk '{print $0}'
P.S. Dette behandler variabelen som en filinput.
ENVIRON
inputSom TrueY skriver, kan du bruke ENVIRON
til å skrive ut Environment Variables.
Hvis du setter en variabel før du kjører AWK, kan du skrive den ut slik:
X=MyVar
awk 'BEGIN{print ENVIRON["X"],ENVIRON["SHELL"]}'
MyVar /bin/bash
ARGV
inputSom Steven Penny skriver, kan du bruke ARGV
for å få dataene inn i awk:
v="my data"
awk 'BEGIN {print ARGV[1]}' "$v"
my data
For å få dataene inn i selve koden, ikke bare BEGIN:
v="my data"
echo "test" | awk 'BEGIN{var=ARGV[1];ARGV[1]=""} {print var, $0}' "$v"
my data test
Du kan bruke en variabel i awk
-koden, men den er rotete og vanskelig å lese, og som Charles Duffy
påpeker, kan denne versjonen også være et offer for kodeinjeksjon. Hvis noen legger til dårlige ting i variabelen, vil den bli utført som en del av awk
-koden.
Dette fungerer ved å trekke ut variabelen i koden, slik at den blir en del av den.
Hvis du vil lage en awk
som endres dynamisk med bruk av variabler, kan du gjøre det på denne måten, men IKKE bruk den for normale variabler.
variable="line one\nline two"
awk 'BEGIN {print "'"$variable"'"}'
line one
line two
Her er et eksempel på kodeinjeksjon:
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
Du kan legge til mange kommandoer til awk
på denne måten. Til og med få den til å krasje med ikke gyldige kommandoer.
Det er alltid bra å sette variabelen "$variable" i doble anførselstegn. Hvis ikke vil flere linjer bli lagt til som en lang enkelt linje.
Eksempel:
var="Line one
This is line two"
echo $var
Line one This is line two
echo "$var"
Line one
This is line two
Andre feil du kan få uten doble anførselstegn:
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
Og med enkelt anførselstegn utvides ikke verdien av variabelen:
awk -v var='$variable' 'BEGIN {print var}'
$variable
Bruk en av disse avhengig av hvordan du vil at backslashes i shell-variablene skal håndteres (avar
er en awk-variabel, svar
er en shell-variabel):
awk -v avar="$svar" '... avar ...' file
awk 'BEGIN{avar=ARGV[1];ARGV[1]=""}... avar ...' "$svar" file
Se http://cfajohnson.com/shell/cus-faq-2.html#Q24 for detaljer og andre alternativer. Den første metoden ovenfor er nesten alltid det beste alternativet og har den mest åpenbare semantikken.
Du kan sende inn kommandolinjealternativet -v
med et variabelnavn (v
) og en verdi (=
) for miljøvariabelen ("${v}"
):
% awk -vv="${v}" 'BEGIN { print v }'
123test
Eller for å gjøre det tydeligere (med langt færre v
):
% environment_variable=123test
% awk -vawk_variable="${environment_variable}" 'BEGIN { print awk_variable }'
123test