È possibile utilizzare la funzione bash allinterno di AWK in qualche modo?
File di esempio (string, int, int , int)
Mike 247808 247809 247810
Tentativo di convertire i valori da decimale a esadecimale.
Funzione definita in .bashrc
o in uno script di shell.
$ awk "{print $1 ; d2h($2)}" file awk: calling undefined function d2h input record number 1, file file source line number 1
Answer
Prova a utilizza la funzione system()
:
awk "{printf("%s ",$1); system("d2h " $2)}" file
Nel tuo caso system
chiama d2h 247808
e aggiungi loutput di questo comando all printf
output:
Mike 3C800
MODIFICA:
poiché system
utilizza sh
invece di bash
Non riesco “a trovare un modo per accedere a .bashrc
. Ma puoi comunque utilizzare le funzioni del tuo attuale script bash:
#!/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:
Non lo so perché, ma questo non funziona sul mio Ubuntu 16.04. Questo è strano, perché prima funzionava su Ubuntu 14.04.
Commenti
Rispondi
Puoi chiamare bash da awk e usare il suo output. Questo è ovviamente pericoloso dal punto di vista delle prestazioni se accade troppo spesso. Citando la pagina man:
command | getline [var]
Esegui il comando piping loutput in $ 0 o var,
sarebbe uno script bash che contiene la definizione della funzione ed esegue la funzione.
Risposta
La conversione da decimale a esadecimale è qualcosa che awk
può fare molto bene da solo. E potresti definire una funzione awk
per farlo:
function d2h(d) { return sprintf("%x", d) }
Ora per rispondere alla domanda nel caso generale, per awk
eseguire bash
funzioni, è “necessario awk
per eseguire una bash
shell, che bash
per interpretare la definizione di quella funzione e chiamare quella funzione, con il valore estratto da awk
passato come argomenti.
Non banale.
bash
supporta le funzioni di esportazione tramite lambiente, quindi è disponibile nelle successive chiamate di bash
, quindi questo è un modo per passare la definizione della funzione per il bash
invocato da awk
:
export -f d2h
Gli unici modi in cui awk
può eseguire un comando (bash
h ere) sono con il relativo system("cmd")
, o print... | "cmd"
o "cmd" | getline
. In tutti i casi, awk
esegue una shell per interpretarlo cmd
, ma sarà sh
, non bash
. Quindi devi creare una riga di comando per sh
che sia una bash
invocazione che interpreta un bash
riga di comando per richiamare la funzione, quindi devi stare attento con le virgolette:
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))}"
Se vuoi recuperare loutput della funzione in awk
, devi trasferirlo di nuovo tramite una pipe. Per questo, “d utilizzare cmd | getline
invece di system(cmd)
(che lascia lo stdout di cmd
” inalterato).
cmd | getline line
memorizza una riga (in senso stretto un record , i record sono righe per impostazione predefinita), quindi per ottenere lintero output nei casi in cui è composto da più righe, avresti bisogno di un ciclo come:
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 ..."
Ciò significa eseguire un sh
e uno bash
per ogni chiamata della funzione , quindi sarà piuttosto inefficiente. Sarebbe anche molto più inefficiente che avere bash
leggere e suddividere con un while read loop
:
(unset -v IFS; while read -r a b rest; do printf "%s\n" "$a" d2h "$b" done < file)
Tieni inoltre presente che, a partire da shellshock, bash
ora esporta funzioni in variabili di ambiente denominate come BASH_FUNC_d2h%%
. Alcune sh
implementazioni tra cui mksh
e versioni più recenti di dash
remove quelle variabili dambiente dallambiente:
$ 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
Quindi, invece di fare affidamento sulla fragile funzione di esportazione della funzione, potresti passare la definizione della funzione in qualche altro modo. Potrebbe essere tramite una variabile di ambiente con un nome normale:
BASH_FUNCTIONS=$(typeset -f d2h) awk " ... cmd = "exec bash -c "\""eval \"$BASH_FUNCTIONS\";" \ "d2h \"$1\""\"" bash " shquote($2) ..."
Risposta
Prova a farlo:
awk "{print $1 ; printf "%x\n", $2}" file
AFAIK, non puoi “usare una bash funzione in awk ma solo uno script. Puoi utilizzare una funzione awk se necessario.
Rispondi
Utilizzando una funzione bash definita dallutente inside awk
Dichiarazione di non responsabilità: mi rendo conto che questo non è ciò che lOP sta cercando di fare, ma Google condurrà altri come me a questa risposta.
Situazione
Hai uno bash
script organizzato con funzioni (perché non odi te stesso o [la maggior parte] dei colleghi) e almeno una di queste funzioni deve chiamare un altro da awk
.
Soluzione
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
Risultato
$ ./example.sh 1. doin" it and 2. doin" it and 3. doin" it well
Commenti
- io rappresenta il Queens, è cresciuta a Brooklyn
Answer
Solo un rapido esempio per dimostrare @HaukeLaging “s command|getline
:
- lascia che linput sia:
Dear friends my name is `id -nu` and today is `date "+%Y-%m-%d"`.
dove stiamo seguendo la sintassi della shell, nellinput,
`command`
è usato per denotare comandi inline da sostituire con il risultato di la sua esecuzione.
- Possiamo espandere il comando della shell inline con:
#!/usr/bin/gawk -f BEGIN { FS ="`"; } NF==3 { $2 | getline $2 } { print }
- Utilizzo (dopo il solito chmod):
$ expand-inline input Dear friends my name is jjoao and today is 2018-01-15.
Risposta
Questo ti darà buone possibilità.
cat ../logs/em2.log.1 |grep -i 192.168.21.15 |awk "{system("date"); print $1}"
la funzione di sistema ti consente di analizzare il comando bash allinterno di awk stream.
Risposta
Questa risposta è per GNU awk, ma altre versioni possono implementare lo stesso trucco. Lidea è che fintanto che il lato destro del tubo è esattamente lo stesso e non esce, awk non chiude il tubo. Ma se è diverso, aprirà un nuovo tubo. Ad esempio, se digiti:
awk "BEGIN{ shell= "/bin/bash" } { print $0 | "/bin/bash" } END { print "echo $a" | " /bin/bash" }"
puoi digitare:
a=5 echo $a
e ottenere la risposta attesa (?) 5: nessuna nuova shell è stata generata. Ma nella sezione FINE, ho digitato uno spazio extra, quindi lRHS del tubo è diverso e viene generata una nuova shell senza alcun valore per la variabile a (e quindi stamperà una riga vuota alluscita. Non riesco a trovarla nella documentazione, ma il modo consigliato di usare pipe a lungo termine è come ho fatto io: inserire il comando nella sezione BEGIN in una variabile e riutilizzare quella variabile.
Dare una funzione definita dallutente a una sessione bash e quindi riutilizzarlo è un esercizio lasciato al lettore 🙂
d2h
fosse un eseguibile, ma non se fosse ‘ sa ” funzione definita in .bashrc o nello script di shell “.source
) ma posso ‘ figura capire perché ‘ t funziona con.bashrc
.$2
finisce per essere interpretato come codice della shell.export -f d2h
‘ non funziona, puoi farlo come per ksh / zsh: (\ 42 e \ 47 sono i codici di escape per virgolette semplici e doppie)CODE=$(typeset -f d2h) awk ' { system("bash -c \47eval \42$CODE\42; d2h \42"$2"\42\47") }'