386 Stimmen

Wie verwende ich Shell-Variablen in einem Awk-Skript?

Ich habe einige Möglichkeiten gefunden, externe Shell-Variablen an ein awk-Skript zu übergeben, aber ich bin verwirrt über ' und ".

Zuerst habe ich es mit einem Shell-Skript versucht:

$ v=123test
$ echo $v
123test
$ echo "$v"
123test

Dann habe ich es mit awk versucht:

$ awk 'BEGIN{print "'$v'"}'
$ 123test
$ awk 'BEGIN{print '"$v"'}'
$ 123

Warum gibt es einen Unterschied?

Zuletzt habe ich dies versucht:

$ awk 'BEGIN{print " '$v' "}'
$  123test
$ awk 'BEGIN{print ' "$v" '}'
awk: cmd. line:1: BEGIN{print
awk: cmd. line:1:             ^ unerwartete neue Zeile oder Ende des Strings 

Das verwirrt mich.

644voto

Jotne Punkte 39246

# Hineinholen von Shell-Variablen in awk kann auf verschiedene Arten erfolgen. Einige sind besser als andere. Dies sollte die meisten abdecken. Wenn Sie einen Kommentar haben, lassen Sie ihn bitte unten.                                                                                      v1.5


Verwendung von -v (Der beste Weg, am portabelsten)

Verwenden Sie die Option -v: (P.S. verwenden Sie ein Leerzeichen nach -v, oder es wird weniger portabel. z.B. awk -v var= nicht awk -vvar=)

variable="Zeile eins\nZeile zwei"
awk -v var="$variable" 'BEGIN {print var}'
Zeile eins
Zeile zwei

Dies sollte mit den meisten awk kompatibel sein, und die Variable ist auch im BEGIN-Block verfügbar:

Wenn Sie mehrere Variablen haben:

awk -v a="$var1" -v b="$var2" 'BEGIN {print a,b}'

Warnung. Wie Ed Morton schreibt, werden Escape-Sequenzen interpretiert, sodass \t zu einem echten Tab wird und nicht zu \tENVIRON[] verwenden oder darauf über ARGV[] zugreifen

PS Wenn Sie einen senkrechten Strich oder andere reguläre Ausdrucks-Metazeichen als Separator wie |?( usw. haben, müssen sie doppelt maskiert werden. Zum Beispiel werden 3 senkrechte Striche ||| zu -F'\\|\\|\\|'. Sie können auch -F"[|][|][|]" verwenden.

Beispiel zum Abrufen von Daten aus einem Programm/Funktion in awk (hier wird das Datum verwendet)

awk -v time="$(date +"%F %H:%M" -d '-1 minute')" 'BEGIN {print time}'

Beispiel zum Testen des Inhalts einer Shell-Variable als regulärer Ausdruck:

awk -v var="$variable" '$0 ~ var{print "gefunden"}'

Variable nach Code-Block

Hier wird die Variable nach dem awk-Code erhalten. Dies funktioniert gut, solange Sie die Variable nicht im BEGIN-Block benötigen:

variable="Zeile eins\nZeile zwei"
echo "Eingabedaten" | awk '{print var}' var="${variable}"
oder
awk '{print var}' var="${variable}" Datei
  • Hinzufügen mehrerer Variablen:

awk '{print a,b,$0}' a="$var1" b="$var2" Datei

  • Auf diese Weise können Sie auch für jede Datei einen anderen Feldtrenner FS festlegen.

awk 'irgendwelcher Code' FS=',' Datei1.txt FS=';' Datei2.ext

  • Variable nach dem Code-Block funktioniert nicht für den BEGIN-Block:

echo "Eingabedaten" | awk 'BEGIN {print var}' var="${variable}"


Here-String

Variable kann auch mittels eines Here-Strings aus Shells, die sie unterstützen (einschließlich Bash), zu awk hinzugefügt werden:

awk '{print $0}' <<< "$variable"
test

Dies entspricht:

printf '%s' "$variable" | awk '{print $0}'

P.S. dies behandelt die Variable als Dateieingabe.


ENVIRON-Eingabe

Wie TrueY schreibt, können Sie ENVIRON verwenden, um Umgebungsvariablen auszugeben. Indem Sie eine Variable vor dem Ausführen von AWK setzen, können Sie sie so ausgeben:

export X=MeineVar
awk 'BEGIN{print ENVIRON["X"],ENVIRON["SHELL"]}'

oder für eine nicht exportierte Variable:

x=MeineVar
x="$x" awk 'BEGIN{print ENVIRON["x"],ENVIRON["SHELL"]}'

ARGV-Eingabe

Wie Steven Penny schreibt, können Sie ARGV verwenden, um die Daten in awk zu bringen:

v="meine Daten"
awk 'BEGIN {print ARGV[1]}' "$v"

Um die Daten in den Code selbst zu bringen, nicht nur im BEGIN:

v="meine Daten"
echo "test" | awk 'BEGIN{var=ARGV[1];ARGV[1]=""} {print var, $0}' "$v"

Variable innerhalb des Codes: MIT VORSICHT VERWENDEN

Sie können eine Variable im awk-Code verwenden, aber es ist unordentlich und schwer zu lesen, und wie Charles Duffy hervorhebt, könnte diese Version auch Opfer von Codeinjektion sein. Wenn jemand Schadcode zur Variable hinzufügt, wird er als Teil des awk-Codes ausgeführt.

Dies funktioniert, indem die Variable im Code extrahiert wird, damit sie zu einem Teil davon wird.

Wenn Sie ein awk erstellen möchten, das sich dynamisch mit Hilfe von Variablen ändert, können Sie es auf diese Weise tun, aber VERWENDEN Sie es NICHT für normale Variablen.

variable="Zeile eins\nZeile zwei"
awk 'BEGIN {print "'"$variable"'"}'

Hier ist ein Beispiel für Codeinjektion:

variable='Zeile eins\nZeile zwei" ; for (i=1;i<=1000;++i) print i"'
awk 'BEGIN {print "'"$variable"'"}'

Auf diese Weise können Sie viele Befehle zu awk hinzufügen. Sogar machen Sie es abstürzen mit nicht gültigen Befehlen.

Eine legitime Verwendung dieses Ansatzes kann jedoch darin bestehen, wenn Sie ein Symbol an awk übergeben möchten, das auf eine Eingabe angewendet werden soll, z. B. einen einfachen Taschenrechner:

$ calc() { awk -v x="$1" -v z="$3" 'BEGIN{ print x '"$2"' z }'; }

$ calc 2.7 '+' 3.4
6.1

$ calc 2.7 '*' 3.4
9.18

Es gibt keine Möglichkeit, dies mit einer awk-Variablen zu tun, die mit dem Wert einer Shell-Variable befüllt ist. Sie MÜSSEN die Shell-Variable erweitern lassen, um ein Teil des Textes des awk-Skripts zu werden, bevor awk ihn interpretiert. (siehe Kommentar unten von Ed M.)


Zusätzliche Informationen:

Verwendung von doppelten Anführungszeichen

Es ist immer gut, die Variable doppelt in Anführungszeichen zu setzen "$variable"
Ansonsten werden mehrere Zeilen als eine lange einzelne Zeile hinzugefügt.

Beispiel:

var="Zeile eins
Dies ist Zeile zwei"

echo $var
Zeile eins Dies ist Zeile zwei

echo "$var"
Zeile eins
Dies ist Zeile zwei

Weitere Fehler, die Sie ohne doppelte Anführungszeichen erhalten können:

variable="Zeile eins\nZeile zwei"
awk -v var=$variable 'BEGIN {print var}'
awk: cmd. line:1: one\nline
awk: cmd. line:1:    ^ backslash not last character on line
awk: cmd. line:1: one\nline
awk: cmd. line:1:    ^ syntax error

Und mit einfachem Anführungszeichen wird der Wert der Variablen nicht erweitert:

awk -v var='$variable' 'BEGIN {print var}'
$variable

Weitere Informationen zu AWK und Variablen

Lesen Sie dieses FAQ.

34voto

TrueY Punkte 7005

Es scheint, dass das altbewährte ENVIRON awk eingebaute Hash überhaupt nicht erwähnt wird. Ein Beispiel für seine Verwendung:

$ X=Solaris awk 'BEGIN{print ENVIRON["X"], ENVIRON["TERM"]}'
Solaris rxvt

10voto

Johnsyweb Punkte 128606

Sie könnten die Befehlszeilenoption -v mit einem Variablennamen (v) und einem Wert (=) der Umgebungsvariable ("${v}") übergeben:

% awk -vv="${v}" 'BEGIN { print v }'
123test

Oder um es klarer zu machen (mit weit weniger v):

% environment_variable=123test
% awk -vawk_variable="${environment_variable}" 'BEGIN { print awk_variable }'
123test

6voto

Zombo Punkte 1

Sie können ARGV nutzen:

v=123test
awk 'BEGIN {print ARGV[1]}' "$v"

Beachten Sie, dass wenn Sie im Body fortfahren möchten, müssen Sie ARGC anpassen:

awk 'BEGIN {ARGC--} {print ARGV[2], $0}' file "$v"

1voto

edib Punkte 674

Ich habe die Antwort von @Jotne für die "for-Schleife" geändert.

for i in `seq 11 20`; do host myserver-$i | awk -v i="$i" '{print "myserver-"i" " $4}'; done

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X