Utilizarea funcției bash shell în AWK

Este posibil să folosiți cumva funcția bash în AWK?

Exemplu de fișier (șir, int, int , int)

Mike 247808 247809 247810 

Încercarea de a converti valorile din zecimal în hexazecimal.

Funcția definită fie în .bashrc sau în script shell.

$ awk "{print $1 ; d2h($2)}" file awk: calling undefined function d2h input record number 1, file file source line number 1 

Răspuns

Încercați să utilizați funcția system():

awk "{printf("%s ",$1); system("d2h " $2)}" file 

În cazul dvs. system apelați d2h 247808 și apoi adăugați ieșirea acestei comenzi la printf ieșire:

Mike 3C800 

EDIT:

Deoarece system folosește sh în loc de bash Nu pot găsi o modalitate de a accesa .bashrc. Dar puteți utiliza în continuare funcții din scriptul bash curent:

#!/bin/bash d2h() { # do some cool conversion here echo "$1" # or just output the first parameter } export -f d2h awk "{printf("%s ",$1); system("bash -c "\""d2h "$2""\""")}" file 

EDIT 2:

Nu știu de ce, dar acest lucru nu funcționează pe Ubuntu 16.04. Acest lucru este ciudat, deoarece a funcționat pe Ubuntu 14.04.

Comentarii

  • Acest lucru ar putea funcționa dacă d2h au fost executabile, dar nu dacă funcția ‘ sa ” a fost definită fie în .bashrc, fie în scriptul shell „.
  • @MichaelHomer da, ai dreptate. Datorită comentariului dvs. mi-am dat seama că am răspuns la întrebarea pe care nimeni nu a pus-o. Dar am găsit o modalitate de a utiliza funcțiile din scriptul curent (și posibil din alte scripturi prin source), dar pot ‘ f figura de ce nu ‘ nu funcționează cu .bashrc.
  • Că ‘ s, de asemenea, o vulnerabilitate de injecție de comandă, deoarece conținutul $2 ajunge să fie interpretat ca un cod shell.
  • Dacă export -f d2h nu funcționează ‘ nu funcționează, o puteți face ca pentru ksh / zsh: (\ 42 și \ 47 sunt codurile de evacuare pentru ghilimele simple și duble) CODE=$(typeset -f d2h) awk ' { system("bash -c \47eval \42$CODE\42; d2h \42"$2"\42\47") }'

Răspuns

Puteți apela bash din awk și utilizați ieșirea acestuia. Acest lucru este evident periculos din perspectiva performanței dacă se întâmplă prea des. Citând pagina de manual:

command | getline [var] 

Rulați comanda canalizând ieșirea fie în $ 0, fie în var,

comanda ar fi un script bash care conține definiția funcției și execută funcția.

Răspuns

Conversia de la zecimal la hexazecimal este ceva ce awk poate face foarte bine. Și ați putea defini o funcție awk pentru a o face:

 function d2h(d) { return sprintf("%x", d) }  

Acum pentru a răspunde la întrebarea în cazul general, pentru ca awk să ruleze bash funcții, ar trebui să aveți awk pentru a executa un shell bash, care bash pentru a interpreta definiția acelei funcții și a apela acea funcție, cu valoarea extrasă de awk transmisă ca argumente.

Nu banal.

bash acceptă exportul funcțiilor prin mediu, deci este disponibil în invocațiile ulterioare ale bash, astfel încât să fie o modalitate de a trece definiția funcției la bash invocată de awk:

export -f d2h 

Singurele modalități prin care awk poate executa o comandă (bash h ere) sunt cu system("cmd") sau print... | "cmd" sau "cmd" | getline. În toate cazurile, awk rulează un shell pentru a interpreta că cmd, dar va fi sh, nu bash. Deci, trebuie să construiți o linie de comandă pentru sh care este o invocație bash care interpretează o bash linie de comandă pentru a invoca funcția, deci trebuie să aveți grijă la citarea:

export -f d2h <file awk -v q=""" " function shquote(s) { gsub(q, q "\\" q q, s) return q s q } {print $1; system("exec bash -c "\""d2h \"$1\""\"" bash " shquote($2))}" 

Dacă doriți să obțineți ieșirea funcției în awk, ar trebui să-l transferați înapoi printr-o conductă. Pentru aceasta, ar trebui să utilizați cmd | getline în loc de system(cmd) (care lasă stdout cmd” neatins).

cmd | getline line stochează o linie (strict vorbind o înregistrare , înregistrările fiind linii în mod implicit), deci pentru a obține întreaga ieșire în cazurile în care este format din mai multe linii, ai avea nevoie de o buclă precum:

 awk "... cmd = "exec bash -c "\""d2h \"$1\""\"" bash " shquote($2) output = "" while ((cmd | getline line) > 0) { output = output line RS } sub(RS "$", "", output) # remove the last newline ..."  

Asta înseamnă să rulați câte un sh și unul bash pentru fiecare invocare a funcției , deci va fi destul de ineficient. Acest lucru ar ajunge să fie chiar mai mult ineficient decât ca bash să citească și să împartă cu un while read loop:

(unset -v IFS; while read -r a b rest; do printf "%s\n" "$a" d2h "$b" done < file) 

De asemenea, rețineți că, de la Shellshock, bash exportă acum funcții în variabile de mediu numite ca BASH_FUNC_d2h%%. Unele sh implementări, inclusiv mksh și versiuni mai noi ale dash eliminare acele variabile de mediu din mediu:

$ env "foo%%=bar" dash -c "printenv foo%%" $ env "foo%%=bar" mksh -c "printenv foo%%" $ env "foo%%=bar" zsh -c "printenv foo%%" bar $ env "foo%%=bar" bash -c "printenv foo%%" bar 

Deci, în loc să vă bazați pe caracteristica de export a funcției slabe, puteți trece definiția funcției în alt mod. Ar putea fi printr-o variabilă de mediu cu un nume obișnuit:

 BASH_FUNCTIONS=$(typeset -f d2h) awk " ... cmd = "exec bash -c "\""eval \"$BASH_FUNCTIONS\";" \ "d2h \"$1\""\"" bash " shquote($2) ..."  

Răspuns

Încercați să faceți acest lucru:

awk "{print $1 ; printf "%x\n", $2}" file 

AFAIK, nu puteți folosi un bash funcție în awk, dar numai un script. Puteți utiliza o funcție awk dacă este necesar.

Răspuns

Utilizarea unei funcții bash definite de utilizator inside awk

Disclaimer: Îmi dau seama că nu asta încearcă să facă OP, dar Google îi va conduce pe alții ca mine la acest răspuns.

Aveți un script bash care este organizat cu funcții (deoarece nu vă urăști pe voi sau pe [majoritatea] colegilor) și cel puțin una dintre aceste funcții trebuie să sunați la altul din awk.

Soluție

Script

#!/bin/env bash # The main function - it"s a sound pattern even in BASH main(){ # In the awk command I do some tricky things with single quotes. Count carefully... # The first $0 is outside the single quotes so it is the name of the current bash script. # The second $0 is inside the single quotes so it is awk"s current line of input. awk "{printf("%s. ", ++c); system(""$0" --do"); print $0}"<<-PRETEND_THIS_IS_AN_INPUT_STREAM and and well PRETEND_THIS_IS_AN_INPUT_STREAM } # functionized to keep things DRY doit(){ echo -n "doin" it " } # check for a command switch and call different functionality if it is found if [[ $# -eq 1 && $1 == "--do" ]]; then doit else main fi 

Output

$ ./example.sh 1. doin" it and 2. doin" it and 3. doin" it well 

Comentarii

  • eu reprezintă Queens, ea a fost crescută în Brooklyn

Răspuns

Doar un exemplu rapid pentru a demonstra @HaukeLaging „s command|getline:

  1. permiteți introducerea să fie:
Dear friends my name is `id -nu` and today is `date "+%Y-%m-%d"`. 

unde urmărim sintaxa shell, în intrare,

`command` 

este folosit pentru a indica comenzi inline care trebuie înlocuite cu rezultatul execuția sa.

  1. Putem extinde comanda shell inline prin:
#!/usr/bin/gawk -f BEGIN { FS ="`"; } NF==3 { $2 | getline $2 } { print } 
  1. Utilizare (după chmod obișnuit):
$ expand-inline input Dear friends my name is jjoao and today is 2018-01-15. 

Răspuns

Acest lucru vă va oferi șanse mari.

cat ../logs/em2.log.1 |grep -i 192.168.21.15 |awk "{system("date"); print $1}" 

funcția de sistem vă permite să analizați comanda bash în fluxul awk.

Răspuns

Acest răspuns este pentru GNU awk, dar alte versiuni pot implementa același truc. Ideea este că, atâta timp cât partea dreaptă a conductei este exact aceeași și nu „iese, awk nu închide conducta. Dar dacă este diferit, va deschide o nouă conductă. De exemplu, dacă tastați:

awk "BEGIN{ shell= "/bin/bash" } { print $0 | "/bin/bash" } END { print "echo $a" | " /bin/bash" }" 

puteți tasta:

a=5 echo $a 

și obțineți răspunsul așteptat (?) 5: nu a apărut nicio coajă nouă. Dar în secțiunea END, am tastat un spațiu suplimentar, astfel încât RHS-ul țevii este diferit și apare un nou shell fără nicio valoare pentru variabila a (și astfel se va imprima o linie goală la ieșire. Nu o pot găsi în documentație, dar modul recomandat de a utiliza conducte pe termen lung este așa cum am: pune comanda în secțiunea BEGIN într-o variabilă și refolosește acea variabilă. apoi refolosirea acestuia este un exercițiu lăsat în seama cititorului 🙂

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *