Použití funkce bash shell uvnitř AWK

Je možné nějak použít funkci bash uvnitř AWK?

Příklad souboru (řetězec, int, int , int)

Mike 247808 247809 247810 

Pokouší se převádět hodnoty z desítkových na šestnáctkové.

Funkce definovaná buď v .bashrc nebo ve skriptu prostředí.

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

Odpověď

Zkuste použijte system() funkci:

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

Ve vašem případě system bude zavolejte d2h 247808 a poté připojte výstup tohoto příkazu k printf výstupu:

Mike 3C800 

EDIT:

Protože system používá sh místo bash Nemohu najít způsob přístupu k .bashrc. Stále však můžete používat funkce z vašeho aktuálního bash skriptu:

#!/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:

Nevím proč, ale to nefunguje na mém Ubuntu 16.04. To je zvláštní, protože to dříve fungovalo na Ubuntu 14.04.

Komentáře

  • To by mohlo fungovat, pokud d2h byl spustitelný soubor, ale ne, pokud je ‚ sa “ funkce definována buď v .bashrc, nebo ve skriptu prostředí „.
  • @MichaelHomer ano, máte pravdu. Díky tvému komentáři jsem si uvědomil, že jsem odpověděl na otázku, kterou nikdo nepoložil. Ale našel jsem způsob, jak používat funkce z aktuálního skriptu (a případně z jiných skriptů pomocí source), ale mohu ‚ f obrázek proč to ‚ nefunguje s .bashrc.
  • To ‚ s také zranitelnost při vkládání příkazů, protože obsah $2 se nakonec interpretuje jako kód shellu.
  • If export -f d2h nefunguje ‚, můžete to udělat jako pro ksh / zsh: (\ 42 a \ 47 jsou únikové kódy pro jednoduché a dvojité uvozovky) CODE=$(typeset -f d2h) awk ' { system("bash -c \47eval \42$CODE\42; d2h \42"$2"\42\47") }'

Odpověď

Můžete volat bash z awk a použít jeho výstup. To je z hlediska výkonu zjevně nebezpečné, pokud k němu dochází příliš často. Cituji manuálovou stránku:

command | getline [var] 

Spusťte příkaz, který výstup přesměruje na $ 0 nebo var,

příkaz by byl bash skript, který obsahuje definici funkce a provede funkci.

Odpovědět

Převod z desítkového na šestnáctkový je něco, co awk dokáže velmi dobře. K tomu můžete definovat funkci awk :

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

Chcete-li nyní odpovědět na otázku obecně, pro awk spustit bash musíte awk spustit bash shell, který bash interpretovat definici této funkce a volat tuto funkci s hodnotou extrahovanou awk předanou jako argumenty.

Není triviální.

bash podporuje funkce exportu přes prostředí, takže je k dispozici v následných vyvoláních bash, takže je jen jeden způsob, jak předat definice funkce bash vyvolaná awk:

export -f d2h 

Jediné způsoby, jak awk provést příkaz (bash h ere) are with its system("cmd"), nebo print... | "cmd" nebo "cmd" | getline. Ve všech případech awk spustí prostředí pro interpretaci cmd, ale bude to sh, nikoli bash. Musíte tedy zkonstruovat příkazový řádek pro sh, což je bash vyvolání, které interpretuje bash příkazový řádek k vyvolání funkce, takže při citování musíte být opatrní:

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))}" 

Pokud chcete získat výstup funkce zpět do awk, musíte jej přenést zpět pomocí potrubí. K tomu použijete cmd | getline místo system(cmd) (který ponechá cmd“ standardní výstup nedotčený).

cmd | getline line ukládá jeden řádek (přísně vzato jeden záznam , záznamy jsou standardně řádky), takže Chcete-li získat celý výstup v případech, kdy je sestaven z několika řádků, potřebujete smyčku, například:

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

To znamená spuštění jednoho sh a jednoho bash pro každé vyvolání funkce , takže to bude docela neefektivní. To by nakonec bylo ještě podstatně neefektivnější, než kdyby bash provedli čtení a rozdělení pomocí while read loop:

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

Všimněte si, že od aplikace Shellshock nyní bash exportují funkce v proměnných prostředí, které jsou pojmenovány jako BASH_FUNC_d2h%%. Některé sh implementace včetně mksh a novějších verzí dash remove tyto proměnné prostředí z prostředí:

$ 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 

Takže místo spoléhání se na funkci exportu chabých funkcí můžete definici funkce předat jiným způsobem. Může to být pomocí proměnné prostředí s obvyklým názvem:

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

Odpovědět

Zkuste to udělat:

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

AFAIK, nemůžete použít bash funkce v awk, ale pouze skript. V případě potřeby můžete použít funkci awk.

Odpověď

Použití uživatelem definované funkce bash inside awk

Zřeknutí se odpovědnosti: Uvědomuji si, že to není to, o co se OP snaží dělat, ale Google k této odpovědi přivede další, jako jsem já.

Situace

Máte bash skript, který je uspořádán s funkcemi (protože nenávidíte sebe nebo [většinu] spolupracovníků) a alespoň 1 z těchto funkcí musí být zavolat další z awk.

Řešení

Skript

#!/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 

Výstup

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

Komentáře

  • já reprezentovat Queens, byla vychována v Brooklynu

Answer

Jen rychlý příklad pro ukázku @HaukeLaging command|getline:

  1. ať je vstup:
Dear friends my name is `id -nu` and today is `date "+%Y-%m-%d"`. 

kde sledujeme syntaxi shellu, na vstupu se

`command` 

používá k označení vložených příkazů , které mají být nahrazeny výsledkem jeho provedení.

  1. Příkaz inline shellu můžeme rozšířit o:
#!/usr/bin/gawk -f BEGIN { FS ="`"; } NF==3 { $2 | getline $2 } { print } 
  1. Použití (po obvyklém chmod):
$ expand-inline input Dear friends my name is jjoao and today is 2018-01-15. 

Odpovědět

To vám dá dobré šance.

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

systémová funkce vám umožní analyzovat příkaz bash ve streamu awk.

Odpověď

Tato odpověď platí pro GNU awk, ale i jiné verze mohou implementovat stejný trik. Myšlenka je, že pokud je pravá strana potrubí přesně stejná a nevychází z ní, awk nezavírá potrubí. Pokud je to však jiné, otevře se nové potrubí. Například pokud zadáte:

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

můžete zadat:

a=5 echo $a 

a získat očekávanou (?) odpověď 5: nebyl vytvořen žádný nový shell. Ale v části KONEC jsem zadal další prostor, takže RHS potrubí je jiný a nový shell je vytvořen bez hodnoty pro proměnnou a (a tak při výstupu vytiskne prázdný řádek. Nemohu ho najít v dokumentace, ale doporučený způsob použití dlouhodobých potrubí je takový, jaký mám: vložte příkaz do sekce ZAČÁTEK do proměnné a tuto proměnnou znovu použijte.

Poskytnutí uživatelem definované funkce relaci bash a pak opětovné použití je cvičení ponechané čtenáři 🙂

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *