Verwendung der Bash-Shell-Funktion in AWK

24

Ist es irgendwie möglich, die Bash-Funktion in AWK zu verwenden?

Beispieldatei (String, Int, Int, Int)

Mike 247808 247809 247810

Es wurde versucht, Werte von dezimal in hexadezimal zu konvertieren.

Funktion, die entweder in .bashrc oder im Shell-Skript definiert ist.

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

awk: Aufrufen der undefinierten Funktion d2h Eingabe Datensatznummer 1, Datei Datei Quelle Zeilennummer 1

sehr klein
quelle

Antworten:

27

Versuchen Sie die system()Funktion zu benutzen :

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

In Ihrem Fall systemwird die d2h 247808Ausgabe dieses Befehls aufgerufen und an die printfAusgabe angehängt:

Mike 3C800

BEARBEITEN:

Als systemAnwendungen shstatt bashkann ich nicht einen Weg , um Zugang zu finden .bashrc. Sie können jedoch weiterhin Funktionen aus Ihrem aktuellen Bash-Skript verwenden:

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

Ich weiß nicht warum, aber das funktioniert auf meinem Ubuntu 16.04 nicht. Das ist seltsam, weil es unter Ubuntu 14.04 funktioniert hat.

akarilimano
quelle
Dies könnte funktionieren, wenn d2hes sich um eine ausführbare Datei handelt, aber nicht, wenn es sich um eine "in .bashrc oder in Shell-Skript definierte Funktion" handelt.
Michael Homer
@MichaelHomer ja, du hast recht. Dank Ihres Kommentars wurde mir klar, dass ich die Frage beantwortet habe, die niemand gestellt hat. Ich habe jedoch eine Möglichkeit gefunden, Funktionen aus dem aktuellen Skript (und möglicherweise aus anderen Skripten über source) zu verwenden, kann jedoch nicht herausfinden, warum dies nicht funktioniert .bashrc.
Akarilimano
2
Dies ist auch eine Sicherheitsanfälligkeit bezüglich Befehlsinjektion, da der Inhalt $2letztendlich als Shell-Code interpretiert wird.
Stéphane Chazelas
8

Sie können bash von awk aus aufrufen und dessen Ausgabe verwenden. Das ist aus Performance-Sicht natürlich gefährlich, wenn es zu oft vorkommt. Zitieren der Manpage:

command | getline [var]

Führen Sie den Befehl aus, der die Ausgabe entweder in $ 0 oder var umleitet.

Befehl wäre ein Bash-Skript, das die Funktionsdefinition enthält und die Funktion ausführt.

Hauke ​​Laging
quelle
Hauke ​​Laging, sehr cool!
JJoao
Ich habe das schon oft benutzt und es funktioniert gut.
Dave Rix
4

Versuchen Sie Folgendes:

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

AFAIK, Sie können in awk keine Bash-Funktion verwenden, sondern nur ein Skript. Bei Bedarf können Sie eine awk-Funktion verwenden.

Gilles Quenot
quelle
3

Verwenden einer benutzerdefinierten Bash-Funktion in awk

Haftungsausschluss: Mir ist klar, dass dies nicht das ist, was das OP versucht, aber Google wird andere wie mich zu dieser Antwort führen.

Lage

Sie haben ein bashSkript, das mit Funktionen organisiert ist (weil Sie sich selbst oder [die meisten] Kollegen nicht hassen) und mindestens eine dieser Funktionen muss eine andere von innen aufrufen awk.

Lösung

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

Ausgabe

$ ./example.sh
1. doin' it and
2. doin' it and
3. doin' it well
Bruno Bronosky
quelle
Ich vertrete Queens, sie wuchs in Brooklyn auf
Bruno Bronosky
3

awkawkFunktionen ausführen können. Damit bashFunktionen ausgeführt werden können, müssen Sie awkeine bashShell ausführen , die bashdie Definition dieser Funktion interpretiert und diese Funktion mit dem von awkübergeben als Argumenten extrahierten Wert aufruft .

Nicht trivial.

bashunterstützt das Exportieren von Funktionen, damit diese in nachfolgenden Aufrufen von verfügbar sind. Auf diese bashWeise können Sie die Definition der Funktion an die bashaufgerufenen übergeben awk:

export -f d2h

Die einzigen Möglichkeiten awk, einen Befehl ( bashhier) auszuführen, sind mit system("cmd"), oder print... | "cmd"oder "cmd" | getline. In allen Fällen awkläuft eine Shell, um das zu interpretieren, cmdwird es aber shnicht sein bash. Sie müssen also eine Befehlszeile erstellen sh, die einen bashAufruf darstellt, der eine bashBefehlszeile zum Aufrufen der Funktion interpretiert. Daher müssen Sie vorsichtig sein, wenn Sie Folgendes angeben:

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

Das bedeutet, dass für jede Zeile eine shund eine ausgeführt werden bashmuss, was ziemlich ineffizient sein wird. Das wäre sogar noch ineffizienter als bashdas Lesen und Teilen mit while read loop:

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

Dies gibt Ihnen gute Chancen.

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

Mit der Systemfunktion können Sie den bash-Befehl in awk stream analysieren.

Mansur Ali
quelle
0

Nur ein kurzer Hack demonstriert @HaukeLaging command|getline :

1) lass die Eingabe sein:

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

In der Eingabe folgt die Shell-Syntax:

`command`

wird verwendet, um zu bezeichnen Inline-Befehle , die durch das Ergebnis seiner Ausführung ersetzt werden sollen.

2) Wir können den Inline-Shell-Befehl folgendermaßen erweitern:

#!/usr/bin/gawk -f

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

3) Verwendung (nach dem üblichen chmod):

$ expand-inline input
Dear friends
my name is jjoao and
today is 2018-01-15.
Joao
quelle