
Ist es irgendwie möglich, die Bash-Funktion in AWK zu verwenden?
Beispieldatei (String, Int, Int, Int)
Mike 247808 247809 247810
Es wird versucht, Werte von Dezimal in Hexadezimal umzuwandeln.
Funktion, die entweder in .bashrc
oder im Shell-Skript definiert ist.
$ awk '{print $1 ; d2h($2)}' file
awk: calling undefined function d2h
input record number 1, file file
source line number 1
Antwort1
Versuchen Sie, die folgende Funktion zu verwenden system()
:
awk '{printf("%s ",$1); system("d2h " $2)}' file
In Ihrem Fall wird die Ausgabe dieses Befehls system
aufgerufen und an die Ausgabe angehängt:d2h 247808
printf
Mike 3C800
BEARBEITEN:
As system
verwendet sh
anstelle von bash
Ich kann keinen Weg finden, darauf zuzugreifen .bashrc
. Sie können aber 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
Hinweis: -f
wird verwendet, umExportieren einer Funktionund nicht eine Variable.
BEARBEITEN 2:
Ich weiß nicht, warum, aber das funktioniert auf meinem Ubuntu 16.04 nicht. Das ist seltsam, denn auf Ubuntu 14.04 hat es früher funktioniert.
Antwort2
Sie können bash von awk aus aufrufen und dessen Ausgabe verwenden. Das ist aus Leistungssicht natürlich gefährlich, wenn es zu oft vorkommt. Zitat aus der Manpage:
command | getline [var]
Führen Sie den Befehl aus und leiten Sie die Ausgabe entweder an $0 oder var weiter.
Befehl wäre ein Bash-Skript, das die Funktionsdefinition enthält und die Funktion ausführt.
Antwort3
Die Konvertierung von Dezimalzahlen in Hexadezimalzahlen kann man awk
ganz einfach selbst durchführen. Und man kann eineawk
Funktion, um dies zu tun:
function d2h(d) {
return sprintf("%x", d)
}
Um die Frage nun allgemein zu beantworten: Zum awk
Ausführen bash
von Funktionen müssten Sie eine Shell awk
ausführen , die die Definition dieser Funktion interpretiert und diese Funktion mit dem extrahierten Wert aufruft, der als Argumente übergeben wird.bash
bash
awk
Nicht trivial.
bash
unterstützt das Exportieren von Funktionen über die Umgebung, so dass es in nachfolgenden Aufrufen von verfügbar ist bash
. Dies ist also eine Möglichkeit, die Definition der Funktion an das bash
von aufgerufene Element zu übergeben awk
:
export -f d2h
Die einzigen Möglichkeiten, einen Befehl ( hier) awk
auszuführen, sind mit seinem , oder oder . In allen Fällen wird eine Shell ausgeführt, um das zu interpretieren , aber es wird sein , nicht . Sie müssen also eine Befehlszeile für konstruieren, die ein Aufruf ist, der eine Befehlszeile interpretiert, um die Funktion aufzurufen, also müssen Sie bei der Verwendung von Anführungszeichen vorsichtig sein:bash
system("cmd")
print... | "cmd"
"cmd" | getline
awk
cmd
sh
bash
sh
bash
bash
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))}'
Wenn Sie die Ausgabe der Funktion zurück in erhalten möchten awk
, müssen Sie sie über eine Pipe zurück übertragen. Dazu verwenden Sie cmd | getline
anstelle von system(cmd)
(wobei cmd
die Standardausgabe von unberührt bleibt).
cmd | getline line
Shopseine Linie(genau genommenein Datensatz, Datensätze sind standardmäßig Zeilen), sodass Sie, um die gesamte Ausgabe in den Fällen zu erhalten, in denen sie aus mehreren Zeilen besteht, eine Schleife wie die folgende benötigen:
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
...'
Das bedeutet, dass für jeden Aufruf der Funktion eins sh
und eins ausgeführt wird bash
, was ziemlich ineffizient ist. Das wäre am Ende sogar noch deutlich ineffizienter, als bash
das Lesen und Aufteilen mit einem while read loop
: durchzuführen.
(unset -v IFS; while read -r a b rest; do
printf '%s\n' "$a"
d2h "$b"
done < file)
Beachten Sie auch, dass seit Shellshock bash
jetzt Exportfunktionen in Umgebungsvariablen mit Namen wie verwendet werden BASH_FUNC_d2h%%
. Einige sh
Implementierungen, einschließlich mksh
und neuere Versionen vondash
entfernendiese Umgebungsvariablen aus der Umgebung:
$ 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
Anstatt sich also auf die schwache Funktion zum Exportieren von Funktionen zu verlassen, können Sie die Funktionsdefinition auch auf andere Weise übergeben. Dies könnte über eine Umgebungsvariable mit einem üblichen Namen erfolgen:
BASH_FUNCTIONS=$(typeset -f d2h) awk '
...
cmd = "exec bash -c '\''eval \"$BASH_FUNCTIONS\";" \
"d2h \"$1\"'\'' bash " shquote($2)
...'
Antwort4
Verwenden einer benutzerdefinierten Bash-Funktion in awk
Haftungsausschluss:Mir ist klar, dass dies nicht das ist, was der OP versucht, aber Google wird andere wie mich zu dieser Antwort führen.
Situation
Sie haben ein bash
Skript, das mit Funktionen organisiert ist (weil Sie weder sich selbst noch [die meisten] Kollegen hassen) und mindestens eine dieser Funktionen muss eine andere von innen heraus 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