web-dev-qa-db-de.com

Variable in der aktuellen Shell von awk setzen

Gibt es eine Möglichkeit, eine Variable in meiner aktuellen Shell aus awk zu setzen?

Ich möchte einige Dateien bearbeiten und Daten ausdrucken. Da ich die gesamte Datei durchgelesen habe, möchte ich die Anzahl der Zeilen speichern - in diesem Fall FNR.

Das passiert, obwohl ich keine Möglichkeit finde, eine Shell-Variable mit FNR value zu setzen. Wenn nicht, müsste ich die Variable FNR aus meiner Ausgabedatei lesen, um num_lines mit dem Wert FNR festzulegen.

Ich habe einige Kombinationen mit awk 'END{system(...)}' ausprobiert, konnte es aber nicht schaffen. Irgendein Weg um dieses herum? 

17
Rubens
$ echo "$var"

$ declare $( awk 'BEGIN{print "var=17"}' )
$ echo "$var"
17

Deshalb sollten Sie declare anstelle von eval verwenden:

$ eval $( awk 'BEGIN{print "echo \"removing all of your files, ha ha ha....\""}' )
removing all of your files, ha ha ha....

$ declare $( awk 'BEGIN{print "echo \"removing all of your files\""}' )
bash: declare: `"removing': not a valid identifier
bash: declare: `files"': not a valid identifier

Beachten Sie im ersten Fall, dass eval die von awk ausgegebenen Zeichenfolgen ausführt, was aus Versehen eine sehr schlechte Sache sein könnte!

22
Ed Morton

Hier ist ein anderer Weg.

Dies ist besonders nützlich, wenn Sie die values ​​Ihrer Variablen in einer single -Variable haben und diese aufteilen möchten. Beispielsweise haben Sie eine Liste von Werten aus einer einzelnen Zeile in einer Datenbank, aus der Sie Variablen erstellen möchten.

val="hello|beautiful|world" # assume this string comes from a database query
read a b c <<< $( echo ${val} | awk -F"|" '{print $1" "$2" "$3}' )

echo $a #hello
echo $b #beautiful
echo $c #world

Wir brauchen in diesem Fall den "Here-String", dh <<<, da der Befehl read nicht aus einer Pipe und stattdessen aus stdin liest

19
Nerrve

Sie können keine Variablen aus einer Subshell in die übergeordnete Shell exportieren. Sie haben jedoch andere Möglichkeiten, darunter:

  1. Führen Sie die Datei erneut mit AWK durch, um Datensätze zu zählen, und verwenden Sie die Befehlsersetzung, um das Ergebnis zu erfassen. Zum Beispiel:

    FNR=$(awk 'END {print FNR}' filename)
    
  2. Drucken SieFNRin der Subshell und parsen Sie die Ausgabe in Ihrem anderen Prozess.
  3. WennFNRder Anzahl der Zeilen entspricht, können Sie wc -l < filename aufrufen, um Ihre Zählung abzurufen.
4
Todd A. Jacobs

Eine Warnung für alle, die versuchen, die Erklärung zu verwenden, wie in mehreren Antworten vorgeschlagen.

eval hat dieses Problem nicht.

Wenn der zum Deklarieren von awk (oder einem anderen Ausdruck) bereitgestellte Ergebnis zu einer leeren Zeichenfolge führt, wird die aktuelle Umgebung deklariert .. _ Dies ist fast sicher nicht das, was Sie möchten.

beispiel: Wenn Ihr awk-Muster in der Eingabe nicht vorhanden ist, werden Sie niemals eine Ausgabe drucken. Das Ergebnis ist ein unerwartetes Verhalten.

Ein Beispiel dafür ....

 unset var
 var=99
 declare $( echo "foobar" | awk '/fail/ {print "var=17"}' )
 echo "var=$var"
var=99
The current environment as seen by declare is printed
and $var is not changed

Eine geringfügige Änderung, um den zu speichernden Wert in einer awk-Variablen zu speichern und am Ende zu drucken, löst dies ....

 unset var
 var=99
 declare $( echo "foobar" | awk '/fail/ {tmp="17"} END {print "var="tmp}' )
 echo "var=$var"
var=
This time $var is unset ie: set to the null string var=''
and there is no unwanted output.

Um dies mit einem passenden Muster zu zeigen

 unset var
 var=99
 declare $( echo "foobar" | awk '/foo/ {tmp="17"} END {print "var="tmp}' )
 echo "var=$var"
var=
This time $var is unset ie: set to the null string var=''
and there is no unwanted output.
3
sbts

Machen Sie awk, um die Zuweisungsaussage auszudrucken:

MYVAR=NewValue

Dann in Ihrem Shell-Skript eval die Ausgabe Ihres awk-Skripts:

eval $(awk ....)
# then use $MYVAR

BEARBEITEN: Leute empfehlen die Verwendung von declare anstelle von eval, um etwas weniger fehleranfällig zu sein, wenn vom inneren Skript etwas anderes als die Zuordnung gedruckt wird. Es ist nur bash, aber es ist in Ordnung, wenn die Shell ist bash und das Skript #!/bin/bash hat, die diese Abhängigkeit richtig angibt.

Die eval $(...)-Variante ist weit verbreitet, wobei bestehende Programme eine Ausgabe generieren, die für eval, nicht jedoch für declare geeignet ist (lesspipe ist ein Beispiel). Deshalb ist es wichtig, es zu verstehen, und die bash-only-Variante ist "zu lokalisiert".

1
Anton Kovalenko

Um hier alles soweit zu synthetisieren, werde ich Ihnen mitteilen, was ich für nützlich halte, um eine Shell-Umgebungsvariable aus einem Skript festzulegen, das eine einzeilige Datei mit awk liest. Natürlich könnte anstelle von /pattern/ ein NR==1 verwendet werden, um die benötigte Variable zu finden.

# export a variable from a script (such as in a .dotfile)
declare $( awk 'NR==1 {tmp=$1} END {print "Shell_VAR=" tmp}' /path/to/file )
export Shell_VAR

Dadurch wird eine massive Ausgabe von Variablen vermieden, wenn ein declare-Befehl ohne Argumente sowie die Sicherheitsrisiken einer blinden eval ausgegeben wird.

1
Merlin

echo "First arg: $ 1" für ((i = 0; i <$ 1; i ++)); echo "inside" echo "Willkommen $ i times." cat man.xml | awk '{x [NR] = $ 0} END {für (i = 2; i <= NR; i ++) {if (x [i] ~ //) {x [i + 1] = "' $ i" " } print x [i]}} '> $ i.xml done echo "abgeschlossen"

0
Hari Prassana