Cum pot folosi variabilele de shell într-un script awk? (Programare, Bash, Shell, Awk)

hqjma a intrebat.

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.

Comentarii

  • Îmi place -v, așa cum se arată mai jos, dar acesta este într-adevăr un exercițiu grozav pentru a ne gândi cum să protejăm lucrurile de shell. Lucrând prin asta, prima mea tăietură folosește backslash-uri pe spații și semne de dolar. Inutil să spun că exemplele de aici au meritat timpul meu. –  > Por Chris.
  • În legătură cu: Diferența dintre ghilimelele simple și duble în awk. –  > Por codeforester.
  • Dacă căutarea dvs. în awk are nevoie de expresie regulată, , nu puteți pune /var/. În schimb, folosiți tilde: awk -v var="$var" '$0 ~ var' –  > Por Noam Manos.
7 răspunsuri
Jotne

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

Citiți acest faq.

Comentarii

  • „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. –  > Por Charles Duffy.
  • 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 {? –  > Por Darion Badlydone.
  • @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. –  > Por Jotne.
  • @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ă –  > Por Darion Badlydone.
  • @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. –  > Por Ed Morton.
TrueY

Se pare că vechiul și bunul ENVIRON hash încorporat nu este menționat deloc. Un exemplu de utilizare a acestuia:

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

Comentarii

  • Aceasta este o sugestie bună, deoarece transmite datele textual. -v nu funcționează atunci când valoarea conține backslash-uri. –  > Por celălalt tip.
  • @thatotherguy Nu știam asta! Am crezut că dacă folosesc awk -v x='cd' ... atunci va fi folosit în mod corespunzător. Dar când x este tipărit awk pică celebrul: awk: warning: escape sequence 'c' treated as plain 'c' mesaj de eroare… Mulțumesc! –  > Por TrueY.
  • 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 utiliza t î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ți ARGV[] sau ENVIRON[]. –  > Por Ed Morton.
Ed Morton

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ă.

Johnsyweb

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 vs):

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

Steven Penny

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"

edib

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

Comentarii

  • 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. –  > Por tripleee.
Sina

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

Comentarii

  • Ghilimelele duble – ghilimele simple – ghilimele duble au fost exact ceea ce aveam nevoie pentru ca al meu să funcționeze. –  > Por user53029.
  • 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ă). –  > Por Jason S.

Tags:, ,