it-swarm.com.de

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 über ' und " verwirrt.

Zuerst versuchte ich es mit einem Shell-Skript:

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

Dann probierte awk:

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

Warum ist der Unterschied?

Zum Schluss habe ich folgendes versucht:

$ awk 'BEGIN{print " '$v' "}'
$  123test
$ awk 'BEGIN{print ' "$v" '}'
awk: cmd. line:1: BEGIN{print
awk: cmd. line:1:             ^ unexpected newline or end of string 

Ich bin darüber verwirrt.

204
hqjma

Shell-Variablen in awk laden

kann auf verschiedene Weise erfolgen. Einige sind besser als andere. Dies sollte die meisten von ihnen abdecken. Wenn Sie einen Kommentar haben, lassen Sie ihn bitte unten.


- Verwenden von -v (Am besten tragbar)

Es verwendet die -v-Option: (P.S. verwendet ein Leerzeichen nach -v oder ist weniger portabel. Beispiel: awk -v var= nicht awk -vvar=)

variable="line one\nline two"
awk -v var="$variable" 'BEGIN {print var}'
line one
line two

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 eine echte tab und nicht \t wird, wenn Sie danach suchen. Kann mit ENVIRON[] gelöst oder über ARGV[] aufgerufen werden


- Variable nach Codeblock

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

variable="line one\nline two"
echo "input data" | awk '{print var}' var="${variable}"
or
awk '{print var}' var="${variable}" file

Dies funktioniert auch mit mehreren Variablen awk '{print a,b,$0}' a="$var1" b="$var2" file

Die Verwendung von Variablen auf diese Weise funktioniert nicht im BEGIN-Block:

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

- Here string

Variable kann auch zu awk hinzugefügt werden, indem Sie hier string verwenden.

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

Das ist das Gleiche wie:

echo "$variable" | awk '{print $0}'

PS, dies bedroht die Variable als Dateieingabe


- ENVIRON-Eingang

Beim TrueY-Schreiben können Sie die Variable ENVIRON verwenden, um den Code Environmental Variables.__ zu drucken. Wenn Sie vor dem Ausführen von AWK eine Variable setzen, können Sie sie wie folgt ausdrucken:

X=MyVar awk 'BEGIN{print ENVIRON["X"],ENVIRON["Shell"]}'
MyVar /bin/bash

- ARGV-Eingang

Während Steven Penny schreibt, können Sie ARGV verwenden, um das Data-Inn in den Hintergrund zu bringen.

v="my data"
awk 'BEGIN {print ARGV[1]}' "$v"
my data

Um den Data Inn zum Code selbst zu bringen, nicht nur zum BEGIN:

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

- Variable innerhalb des Codes: USE WITH CAUTION

Sie können eine Variable innerhalb des awk-Codes verwenden, die jedoch unlesbar und schwer lesbar ist, und wie Charles Duffy darauf hinweist, kann diese Version auch Opfer einer Code-Injektion werden. Wenn jemand der Variablen fehlerhaftes Material hinzufügt, wird dies als Teil des awk-Codes ausgeführt.

Dies funktioniert durch Extrahieren der Variablen im Code, sodass sie Teil davon wird.

Wenn Sie eine awk erstellen möchten, die sich dynamisch mit Hilfe von Variablen ändert, können Sie dies auf folgende Weise tun: Bot verwendet sie NICHT für normale Variablen.

variable="line one\nline two"
awk 'BEGIN {print "'"$variable"'"}'
line one
line two

Hier ist ein Beispiel für die Code-Injektion:

variable='line one\nline two" ; for (i=1;i<=1000;++i) print i"'
awk 'BEGIN {print "'"$variable"'"}'
line one
line two
1
2
3
.
.
1000

Sie können auf diese Weise viele Befehle zu awk hinzufügen. Sogar mit ungültigen Befehlen zum Absturz bringen.


- Zusatzinformation:

Verwendung von Anführungszeichen
Es ist immer gut, die Anführungszeichenvariable "$variable" zu verdoppeln.
Wenn dies nicht der Fall ist, werden mehrere Zeilen als lange einzelne Zeile hinzugefügt.

Beispiel:

var="Line one
This is line two"

echo $var
Line one This is line two

echo "$var"
Line one
This is line two

Andere Fehler können Sie ohne Anführungszeichen erhalten:

variable="line one\nline two"
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

Bei einfachen 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 diese FAQ

362
Jotne

Es scheint, dass der eingebaute Hash aus ENVIRONawk überhaupt nicht erwähnt wird. Ein Beispiel für seine Verwendung:

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

Verwenden Sie eine dieser Optionen, je nachdem, wie Sie umgekehrte Schrägstriche in den Shell-Variablen bearbeiten möchten (avar ist eine awk-Variable, svar ist eine Shell-Variable)

awk -v avar="$svar" '... avar ...' file
awk 'BEGIN{avar=ARGV[1];ARGV[1]=""}... avar ...' "$svar" file

Siehe http://cfajohnson.com/Shell/cus-faq-2.html#Q24 für Einzelheiten und andere Optionen. Die erste Methode oben ist fast immer die beste Option und hat die offensichtlichste Semantik.

8
Ed Morton

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

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

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

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

Sie können ARGV nutzen:

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

Beachten Sie, dass Sie, wenn Sie in den Körper einsteigen möchten, anpassen müssen ARGC:

awk 'BEGIN {ARGC--} {print ARGV[2], $0}' file "$v"
3
Steven Penny
for i in chr{1..22} chrX chrY
do
awk -v chr="$i" '$1==chr' ../snp150.hg19.txt >> $chr.vcf.bed
echo $i
done
0
Shicheng Guo

Ich musste ein Datum am Anfang der Zeilen einer Protokolldatei einfügen und es wird wie folgt ausgeführt:

DATE=$(date +"%Y-%m-%d")
awk '{ print "'"$DATE"'", $0; }' /path_to_log_file/log_file.log

Es kann zum Speichern in eine andere Datei umgeleitet werden

0
Sina

Ich habe gerade @ Jotnes Antwort auf "for loop" geändert. 

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