Ik heb wat manieren gevonden om externe shell variabelen door te geven aan een awk
script, maar ik'ben verward over '
en "
.
Eerst probeerde ik het met een shell script:
$ v=123test
$ echo $v
123test
$ echo "$v"
123test
Daarna probeerde ik het met awk:
$ awk 'BEGIN{print "'$v'"}'
$ 123test
$ awk 'BEGIN{print '"$v"'}'
$ 123
Waarom is het verschil?
Als laatste heb ik dit geprobeerd:
$ 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
Ik ben verward over dit.
Shell variabelen in
awk
krijgenkan op verschillende manieren gedaan worden. Sommige zijn beter dan andere. Dit zou de meeste moeten behandelen. Als je een opmerking hebt, laat die dan hieronder achter.
-v
(De beste manier, meest portable)Gebruik de -v
optie: (P.S. gebruik een spatie na -v
of het zal minder portable zijn. Bijv. awk -v var=
niet awk -vvar=
)
variable="line one\nline two"
awk -v var="$variable" 'BEGIN {print var}'
line one
line two
Dit zou compatibel moeten zijn met de meeste awk
, en de variabele is ook beschikbaar in het BEGIN
blok:
Als je meerdere variabelen hebt:
awk -v a="$var1" -v b="$var2" 'BEGIN {print a,b}'
Waarschuwing. Zoals Ed Morton schrijft, escape sequenties worden geïnterpreteerd zodat tab
een echte tab
wordt en niet tab
als dat is waar je naar zoekt. Kan worden opgelost door ENVIRON[]
te gebruiken of het via ARGV[]
te benaderen
PS Als je drie verticale streepjes als scheidingsteken ||
wilt, kan dat niet ge-escaped worden, dus gebruik -F"[|][|][|]"
Voorbeeld van het ophalen van gegevens uit een programma/functie in
awk
(hier wordt datum gebruikt)
awk -v time="$(date +"%F %H:%M" -d '-1 minute')" 'BEGIN {print time}'
Hier krijgen we de variabele na de awk
code. Dit werkt prima, zolang je de variabele niet nodig hebt in het BEGIN
blok:
variable="line one\nline two"
echo "input data" | awk '{print var}' var="${variable}"
or
awk '{print var}' var="${variable}" file
Dit werkt ook met meerdere variabelen
awk '{print a,b,$0}' a="$var1" b="$var2" bestand
Variabele op deze manier gebruiken werkt niet in BEGIN
blok:
echo "input data" | awk 'BEGIN {print var}' var="${variable}"
Variabelen kunnen ook worden toegevoegd aan awk
met behulp van een here-string van shells die dat ondersteunen (inclusief Bash):
awk '{print $0}' <<< "$variable"
test
Dit is hetzelfde als:
printf '%s' "$variable" | awk '{print $0}'
P.S. dit behandelt de variabele als een bestand input.
ENVIRON
invoerZoals TrueY schrijft, kun je de ENVIRON
gebruiken om omgevingsvariabelen af te drukken.
Als je een variabele instelt voordat je AWK uitvoert, kun je hem als volgt uitprinten:
X=MyVar
awk 'BEGIN{print ENVIRON["X"],ENVIRON["SHELL"]}'
MyVar /bin/bash
ARGV
invoerZoals Steven Penny schrijft, kun je ARGV
gebruiken om de gegevens in awk te krijgen:
v="my data"
awk 'BEGIN {print ARGV[1]}' "$v"
my data
Om de gegevens in de code zelf te krijgen, niet alleen de BEGIN:
v="my data"
echo "test" | awk 'BEGIN{var=ARGV[1];ARGV[1]=""} {print var, $0}' "$v"
my data test
Je kunt een variabele binnen de awk
code gebruiken, maar het is rommelig en moeilijk te lezen, en zoals Charles Duffy
opmerkt, kan deze versie ook een slachtoffer zijn van code injectie. Als iemand slechte dingen aan de variabele toevoegt, zal het worden uitgevoerd als onderdeel van de awk
code.
Dit werkt door de variabele binnen de code te halen, zodat het een deel van de code wordt.
Als je een awk
wilt maken die dynamisch verandert door het gebruik van variabelen, kun je het op deze manier doen, maar gebruik het NIET voor normale variabelen.
variable="line one\nline two"
awk 'BEGIN {print "'"$variable"'"}'
line one
line two
Hier is een voorbeeld van code injectie:
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
Je kunt op deze manier veel commando's aan awk
toevoegen. Je kunt het zelfs laten crashen met ongeldige commando's.
Het's altijd goed om variabele "$variable"
dubbel aan te halen.
Zo niet, dan zullen meerdere regels worden toegevoegd als een lange enkele regel.
Voorbeeld:
var="Line one
This is line two"
echo $var
Line one This is line two
echo "$var"
Line one
This is line two
Andere fouten kun je krijgen zonder dubbele aanhalingstekens:
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
En met enkel aanhalingsteken, wordt de waarde van de variabele niet uitgebreid:
awk -v var='$variable' 'BEGIN {print var}'
$variable
Gebruik een van deze, afhankelijk van hoe u wilt dat backslashes in de shell variabelen worden behandeld (avar
is een awk variabele, svar
is een shell variabele):
awk -v avar="$svar" '... avar ...' file
awk 'BEGIN{avar=ARGV[1];ARGV[1]=""}... avar ...' "$svar" file
Zie http://cfajohnson.com/shell/cus-faq-2.html#Q24 voor details en andere opties. De eerste methode hierboven is bijna altijd je beste optie en heeft de meest voor de hand liggende semantiek.
Je zou de command-line optie -v
kunnen doorgeven met een variabelenaam (v
) en een waarde (=
) van de omgevingsvariabele ("${v}"
):
% awk -vv="${v}" 'BEGIN { print v }'
123test
Of om het duidelijker te maken (met veel minder v
s):
% environment_variable=123test
% awk -vawk_variable="${environment_variable}" 'BEGIN { print awk_variable }'
123test