Am găsit câteva modalități de a trece variabile externe de shell la un script awk
script, dar sunt confuz în legătură cu '
și "
.
În primul rând, am încercat cu un script shell:
$ v=123test
$ echo $v
123test
$ echo "$v"
123test
Apoi am încercat cu awk:
$ awk 'BEGIN{print "'$v'"}'
$ 123test
$ awk 'BEGIN{print '"$v"'}'
$ 123
De ce este diferența?
În cele din urmă am încercat acest lucru:
$ 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
Sunt confuz în legătură cu asta.
Obținerea variabilelor de shell în
awk
se poate face în mai multe moduri. Unele sunt mai bune decât altele. Acest lucru ar trebui să acopere cele mai multe dintre ele. Dacă aveți un comentariu, vă rugăm să lăsați mai jos. v1.5
Utilizarea -v
(Cel mai bun mod, cel mai portabil)
Utilizați -v
opțiune: (P.S. folosiți un spațiu după -v
sau va fi mai puțin portabil. De ex, awk -v var=
nu awk -vvar=
)
variable="line one
line two"
awk -v var="$variable" 'BEGIN {print var}'
line one
line two
Acest lucru ar trebui să fie compatibil cu majoritatea awk
, , iar variabila este disponibilă în BEGIN
de asemenea:
Dacă aveți mai multe variabile:
awk -v a="$var1" -v b="$var2" 'BEGIN {print a,b}'
Avertisment. După cum scrie Ed Morton, secvențele de scăpare vor fi interpretate astfel t
devine un adevărat tab
și nu t
dacă asta este ceea ce căutați. Poate fi rezolvat prin utilizarea ENVIRON[]
sau accesați-o prin ARGV[]
PS Dacă vă plac trei bare verticale ca separator |||
, , aceasta nu poate fi scăpată, așa că folosiți -F"[|][|][|]"
Exemplu de obținere a datelor dintr-un program/funcție han la
awk
(aici se utilizează data)
awk -v time="$(date +"%F %H:%M" -d '-1 minute')" 'BEGIN {print time}'
Variabilă după blocul de cod
Aici se obține variabila după blocul de cod awk
cod. Acest lucru va funcționa bine atâta timp cât nu aveți nevoie de variabilă în blocul BEGIN
bloc:
variable="line one
line two"
echo "input data" | awk '{print var}' var="${variable}"
or
awk '{print var}' var="${variable}" file
- Adăugarea mai multor variabile:
awk '{print a,b,$0}' a="$var1" b="$var2" file
- În acest fel putem seta și un separator de câmpuri diferit.
FS
pentru fiecare fișier.
awk 'some code' FS=',' file1.txt FS=';' file2.ext
- Variabila după blocul de cod nu va funcționa pentru
BEGIN
bloc:
echo "input data" | awk 'BEGIN {print var}' var="${variable}"
Here-string
Variabila poate fi, de asemenea, adăugată la awk
folosind un here-string din shell-urile care le acceptă (inclusiv Bash):
awk '{print $0}' <<< "$variable"
test
Este același lucru cu:
printf '%s' "$variable" | awk '{print $0}'
P.S. acest lucru tratează variabila ca pe o intrare de fișier.
ENVIRON
intrare
După cum scrie TrueY, puteți utiliza opțiunea ENVIRON
pentru a imprima Variabile de mediu.setarea unei variabile înainte de a rula AWK, o puteți imprima astfel:
X=MyVar
awk 'BEGIN{print ENVIRON["X"],ENVIRON["SHELL"]}'
MyVar /bin/bash
ARGV
input
Așa cum scrie Steven Penny, puteți utiliza ARGV
pentru a introduce datele în awk:
v="my data"
awk 'BEGIN {print ARGV[1]}' "$v"
my data
Pentru a introduce datele în codul propriu-zis, nu doar în BEGIN:
v="my data"
echo "test" | awk 'BEGIN{var=ARGV[1];ARGV[1]=""} {print var, $0}' "$v"
my data test
Variabila din cod: A SE UTILIZA CU PRECAUȚIE
Puteți utiliza o variabilă în interiorul codului awk
cod, dar este dezordonat și greu de citit, iar ca și Charles Duffy
subliniază, această versiune poate fi, de asemenea, o victimă a injecției de cod. Dacă cineva adaugă lucruri rele la variabilă, acestea vor fi executate ca parte a codului awk
cod.
Acest lucru funcționează prin extragerea variabilei în cadrul codului, astfel încât să devină parte a acestuia.
Dacă doriți să faceți o variabilă awk
care să se schimbe dinamic odată cu utilizarea variabilelor, o puteți face în acest mod, dar NU o folosiți pentru variabilele normale.
variable="line one
line two"
awk 'BEGIN {print "'"$variable"'"}'
line one
line two
Iată un exemplu de injecție de cod:
variable='line one
line two" ; for (i=1;i<=1000;++i) print i"'
awk 'BEGIN {print "'"$variable"'"}'
line one
line two
1
2
3
.
.
1000
Puteți adăuga o mulțime de comenzi la awk
în acest mod. Chiar și să-l faceți să se blocheze cu comenzi nevalabile.
Informații suplimentare:
Utilizarea ghilimelelor duble
Întotdeauna este bine să folosiți ghilimele duble pentru variabilele "$variable"
În caz contrar, mai multe linii vor fi adăugate ca o singură linie lungă.
Exemplu:
var="Line one
This is line two"
echo $var
Line one This is line two
echo "$var"
Line one
This is line two
Alte erori pe care le puteți obține fără ghilimele duble:
variable="line one
line two"
awk -v var=$variable 'BEGIN {print var}'
awk: cmd. line:1: one
line
awk: cmd. line:1: ^ backslash not last character on line
awk: cmd. line:1: one
line
awk: cmd. line:1: ^ syntax error
Și cu ghilimele simple, nu se extinde valoarea variabilei:
awk -v var='$variable' 'BEGIN {print var}'
$variable
Mai multe informații despre AWK și variabile
- „dezordonat și greu de citit” ignoră problema de securitate mai importantă a injecției de cod atunci când se înlocuiesc direct șiruri de caractere în codul awk. – > .
- citind răspunsul de mai sus, pot rula scriptul meu fără erori, dar nu face treaba: awk -v repo=”$1″ -v tag=”$2″ ‘{sub(/image: registryabx.azurecr. io/{print repo}:([a-z0-9]+)$/, „image: registryabc.azurecr. io/{print repo}:{print tag}”);}1’ ./services/appscompose.yaml >> newcompose.yaml. Este din cauza parantezelor imbricate {? – > .
- @DarionBadlydone Încercați acest lucru
awk -v repo="$1" -v tag="$2" 'BEGIN {print "repo="repo,"tag="tag}'
. Se va vedea dacă se imprimă variabila. Postați o întrebare proprie dacă nu vă puteți da seama. – > . - @Jotne da, imprimă valorile, așa că am încercat în felul următor: awk -v repo=”$1″ -v tag=”$2″ ‘{print „{sub(/image: registryabc.azurecr. io/”repo”:(([a-z0-9-9]+)$/,
imagine: registryabc.azurecr.io/”repo”: „tag”
);}1″}’ ./services/appscompose.yaml >> newcompose.yaml dar nu funcționează așa cum a fost aspectat. Acesta înlocuiește fiecare linie din fișierul sursă cu comanda tipărită – > . - @DarionBadlydone sed este o alegere mult mai proastă decât awk pentru asta, deoarece nu înțelege deloc șirurile literale, vezi is-it-posible-to-escape-regex-metacharacters-reliably-with-sed. Pur și simplu ați avut o sintaxă greșită în scriptul awk pe care l-ați încercat, dacă ați fi postat o întrebare v-am fi putut ajuta – nu ezitați să faceți asta în continuare dacă doriți. – > .
Se pare că vechiul și bunul ENVIRON
awk hash încorporat nu este menționat deloc. Un exemplu de utilizare a acestuia:
$ X=Solaris awk 'BEGIN{print ENVIRON["X"], ENVIRON["TERM"]}'
Solaris rxvt
- Aceasta este o sugestie bună, deoarece transmite datele textual.
-v
nu funcționează atunci când valoarea conține backslash-uri. – > . - @thatotherguy Nu știam asta! Am crezut că dacă folosesc
awk -v x='cd' ...
atunci va fi folosit în mod corespunzător. Dar cândx
este tipărit awk pică celebrul:awk: warning: escape sequence 'c' treated as plain 'c'
mesaj de eroare… Mulțumesc! – > . - Funcționează corect – corect în acest context înseamnă să extindem secvențele de scăpare, pentru că așa se face
-v
a fost conceput să funcționeze astfel încât să puteți utilizat
în variabilă și să se potrivească cu o tabulare literală din date, de exemplu. Dacă nu acesta este comportamentul pe care îl doriți, atunci nu utilizați-v
ci folosițiARGV[]
sauENVIRON[]
. – > .
Folosiți oricare dintre acestea în funcție de modul în care doriți să fie tratate backslash-urile din variabilele shell (avar
este o variabilă awk, svar
este o variabilă shell):
awk -v avar="$svar" '... avar ...' file
awk 'BEGIN{avar=ARGV[1];ARGV[1]=""}... avar ...' "$svar" file
A se vedea http://cfajohnson.com/shell/cus-faq-2.html#Q24 pentru detalii și alte opțiuni. Prima metodă de mai sus este aproape întotdeauna cea mai bună opțiune și are cea mai evidentă semantică.
Ați putea trece în opțiunea de linie de comandă -v
cu un nume de variabilă (v
) și o valoare (=
) a variabilei de mediu ("${v}"
):
% awk -vv="${v}" 'BEGIN { print v }'
123test
Sau, pentru a fi mai clar (cu mult mai puține v
s):
% environment_variable=123test
% awk -vawk_variable="${environment_variable}" 'BEGIN { print awk_variable }'
123test
Puteți utiliza ARGV:
v=123test
awk 'BEGIN {print ARGV[1]}' "$v"
Rețineți că, dacă veți continua în corp, va trebui să ajustațiARGC:
awk 'BEGIN {ARGC--} {print ARGV[2], $0}' file "$v"
Tocmai am schimbat răspunsul lui @Jotne pentru „for loop”.
for i in `seq 11 20`; do host myserver-$i | awk -v i="$i" '{print "myserver-"i" " $4}'; done
- Aceasta pare a fi doar o altă ilustrare a modului în care se poate utiliza Awk’s
-v
opțiune care a fost deja menționată în multe dintre răspunsurile existente. Dacă doriți să arătați cum să rulați Awk într-o buclă, aceasta este o altă întrebare cu adevărat. – > .
Am avut de inserat data la începutul liniilor unui fișier de log și se face ca mai jos:
DATE=$(date +"%Y-%m-%d")
awk '{ print "'"$DATE"'", $0; }' /path_to_log_file/log_file.log
Se poate redirecționa către un alt fișier pentru a salva
- Ghilimelele duble – ghilimele simple – ghilimele duble au fost exact ceea ce aveam nevoie pentru ca al meu să funcționeze. – > .
- Acest lucru a fost deja menționat în răspunsul acceptat ca o metodă pe care nu ar trebui să o utilizați din cauza vulnerabilităților de injectare a codului. Așadar, informațiile de aici sunt redundante (deja descrise în răspunsul acceptat) și incomplete (nu menționează problemele legate de această metodă). – > .
/var/
. În schimb, folosiți tilde:awk -v var="$var" '$0 ~ var'
– > Por Noam Manos.