Utilizzo della funzione shell bash all'interno di AWK


24

È possibile utilizzare la funzione bash in AWK in qualche modo?

File di esempio (stringa, int, int, int)

Mike 247808 247809 247810

Tentativo di convertire i valori da decimale a esadecimale.

Funzione definita in .bashrc o in shell script.

awk '{print $1 ; d2h($2)}' file

awk: chiamata della funzione indefinita d2h input numero record 1, file numero sorgente file file 1

Risposte:


27

Prova a usare la system()funzione:

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

Nel tuo caso systemchiamerà d2h 247808e quindi aggiungerà l'output di questo comando printfall'output:

Mike 3C800

MODIFICARE:

Come systemusi shinvece di bashnon riesco a trovare un modo per accedere .bashrc. Ma puoi ancora usare 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

MODIFICA 2:

Non so perché, ma questo non funziona sul mio Ubuntu 16.04. Questo è strano, perché funzionava su Ubuntu 14.04.


Questo potrebbe funzionare se d2hfosse un eseguibile, ma non se si tratta di una "funzione definita in .bashrc o in shell script".
Michael Homer,

@MichaelHomer sì, hai ragione. Grazie al tuo commento mi sono reso conto di aver risposto alla domanda che nessuno ha posto. Ma ho trovato un modo per usare le funzioni dello script corrente (e possibilmente da altri script tramite source) ma non riesco a capire perché non funzioni .bashrc.
akarilimano,

2
Questa è anche una vulnerabilità nell'iniezione di comandi poiché il contenuto di $2finisce per essere interpretato come codice shell.
Stéphane Chazelas,

8

Puoi chiamare bash da awk e usare il suo output. Questo è ovviamente pericoloso dal punto di vista delle prestazioni se succede troppo spesso. Citando la pagina man:

command | getline [var]

Esegui il comando eseguendo il piping dell'output in $ 0 o var,

Il comando sarebbe uno script bash che contiene la definizione della funzione ed esegue la funzione.


Hauke ​​Laging, molto figo!
JJoao,

L'ho usato molte volte e funziona bene.
Dave Rix,

4

Prova a fare questo:

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

AFAIK, non puoi usare una funzione bash in awk ma solo uno script. È possibile utilizzare una funzione awk se necessario.


3

Utilizzo di una funzione bash definita dall'utente all'interno di awk

Disclaimer: mi rendo conto che questo non è ciò che l'OP sta cercando di fare, ma Google porterà altri come me a questa risposta.

Situazione

Hai uno bashscript organizzato con funzioni (perché non odi te stesso o [la maggior parte] dei colleghi) e almeno 1 di quelle funzioni deve chiamarne un'altra dall'interno awk.

Soluzione

copione

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

Produzione

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

Rappresento Queens, è stata cresciuta a Brooklyn
Bruno Bronosky

3

awkpuò eseguire awkfunzioni. Affinché bashfunzioni, dovresti awkeseguire una bashshell, quella bashper interpretare la definizione di quella funzione, e chiamare quella funzione, con il valore estratto da awkpassato come argomenti.

Non banale.

bashsupporta l'esportazione di funzioni, quindi è disponibile nelle successive invocazioni di bash, quindi è un modo per passare la definizione della funzione a quella bashinvocata da awk:

export -f d2h

Gli unici modi per awkeseguire un comando ( bashqui) sono con il suo system("cmd"), o print... | "cmd"o "cmd" | getline. In tutti i casi, awkcorre un guscio di interpretare che cmd, ma sarà sh, no bash. Quindi è necessario costruire una riga di comando per shquella è bashun'invocazione che interpreta una bashriga di comando per invocare la funzione, quindi è necessario fare attenzione con la citazione:

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

Ciò significa che eseguire uno she uno bashper ogni riga, quindi sarà abbastanza inefficiente. Ciò finirebbe per essere significativamente più inefficiente rispetto a dover bashleggere e dividere con un while read loop:

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

0

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 consente di analizzare il comando bash all'interno del flusso awk.


0

Basta un breve trucco per dimostrare @HaukeLaging command|getline :

1) lascia che input sia:

Dear friends
my name is `id -nu` and
today is `date "+%Y-%m-%d"`.

Dopo la sintassi della shell, nell'input,

`command`

è usato per indicare comandi in linea che devono essere sostituiti dal risultato della sua esecuzione.

2) Possiamo espandere il comando di shell inline:

#!/usr/bin/gawk -f

BEGIN  { FS ="`";        }
NF==3  { $2 | getline $2 }
       { print           }

3) Utilizzo (dopo il solito chmod):

$ expand-inline input
Dear friends
my name is jjoao and
today is 2018-01-15.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.