Awk-Befehl in einer for-Schleife

Ich versuche erfolglos, einen awk -Befehl in einem for Schleife.

Ich habe eine Variable, die eine Reihe von Zeichenfolgen enthält, die ich mit awk schneiden möchte um die Daten zu erhalten.

Ich weiß, wie das geht, aber ich möchte wirklich, dass die Daten nacheinander geschnitten werden.

Also habe ich diese Variable:

var="data1,data2,data3" 

Und hier, wo ich gerade bin:

for ((i=1; i<=3; i++)) do echo $(awk -F, "{print $1}" <<< $var) done 

Ich versuche, die $1 durch die Schleife $i, jedoch ohne Erfolg.

Kommentare

  • Jedes Zeichen zwischen zwei einfachen Anführungszeichen wird als wörtliches Zeichen behandelt.
  • Was ist Ihr wirklicher Anwendungsfall? Eine Schleife über awk erscheint hier unnötig (zum Beispiel in bash könnten Sie eine Parametersubstitution verwenden echo "${var//,/$'\n'}")
  • Tatsächlich enthält die Variable URLs aus einer Zenity-Form. Ich möchte diese URLs separat verwenden, damit ich sie einzeln abrufen kann.
  • Relevant, aber in diesem Fall keine gute Lösung: Gewusst wie Wert zur Laufzeit im AWK-Befehl zuweisen

Antwort

Sie können das erreichen, was Sie sind Versuchen Sie dies, indem Sie im awk-Skript doppelte Anführungszeichen verwenden, um die Shell-Variable einzufügen. Sie möchten immer noch ein Literal $ darin behalten, was Sie tun können, indem Sie es mit Backslash maskieren :

echo $(awk -F, "{print \$$i}" <<<$var) 

Dadurch wird die $i auf 1 erweitert. 2 und 3 in jeder der Iterationen, daher sieht awk $1, $2 und $3, wodurch jedes der Felder erweitert wird.

Eine andere Möglichkeit besteht darin, die Shell-Variable als zu injizieren awk-Variable mit dem Flag -v :

echo $(awk -F, -v i="$i" "{print $i}" <<<$var) 

Damit wird die awk-Variable i dem Inhalt der gleichnamigen Shell-Variablen zugewiesen. Variablen in awk verwenden kein $, das für Felder verwendet wird. $i reicht also aus, um auf das i zu verweisen -thes Feld, wenn i eine Variable in awk ist.

Das Zuweisen einer awk-Variablen mit -v ist im Allgemeinen sicherer Ansatz, insbesondere wenn es beliebige Zeichenfolgen enthalten kann, besteht in diesem Fall ein geringeres Risiko, dass der Inhalt gegen Ihre Absichten als awk-Code ausgeführt wird. Da die Variable in Ihrem Fall jedoch eine einzelne Ganzzahl enthält, ist dies weniger bedenklich.

Eine weitere Option ist die Verwendung einer for -Schleife in awk selbst Weitere Informationen dazu finden Sie in der awk-Dokumentation (oder durchsuchen Sie diese Site).

Kommentare

  • … oder legen Sie den Eingabedatensatz fest Trennzeichen entsprechend awk -v RS='[,\n]' 1 <<< "$var" (oder vielleicht portabler printf "$var" | awk -v RS=, 1)
  • @steeldriver Dieses awk-Skript druckt alle drei Felder unter einmal. Was in Ordnung ist, wenn das OP genau das tut … Am Ende konzentrierte ich die Antwort auf das Extrahieren eines einzelnen Feldes unter der Annahme, dass sie daran interessiert waren, andere Befehle in der Shell-Schleife auszuführen (was möglicherweise der Fall ist) waren die Motivation, überhaupt eine zu verwenden …)
  • Verstanden – das ‚ ist der Grund, warum ich das OP kommentiert habe, um zu klären, was sie wirklich wollen;)
  • Das erste ist eine Injektion (und ein Sicherheitsbedenken), das zweite o ne (mit -v) ist keine Injektion.
  • Danke, Ihre Antwort hat mein Problem gelöst! Zum ersten Mal poste ich hier eine Frage, nachdem ich jahrelang Beiträge gelesen habe. Nicht enttäuscht. Eine so großartige Community!

Antwort

Die Verwendung von awk scheint Wie wäre es unter diesen Umständen mit einer tr und einer while-Schleife:

tr , "\n" <<<"$var" | while read; do echo $REPLY done 

Ausgabe:

data1 data2 data3 

Kommentare

  • Großartig. REPLY ist das Standardargument name für den integrierten Shell-Befehl read.
  • Beachten Sie, dass dies erfordert, dass die Shell eine Standardvariable verwendet, um die Daten von read einzugeben, was bash zufällig tut , aber das ist nicht Standard. Außerdem kann Ihr Befehl read die Daten ändern, wenn sie Backslashes enthalten, und flankierende Leerzeichen aus den Werten entfernen. Es würde auch Werte mit eingebetteten Zeilenumbrüchen als mehrere Werte lesen. Sie benötigen außerdem "$REPLY", um zu verhindern, dass die Shell den Wert aufteilt und eine Dateinamenerweiterung durchführt.

Antwort

kann akzeptieren sowohl j (als Variable) als auch $j (als Feldindex):

 for i in 1 2 3; do echo "$var" | awk -v j=$i -F , "{print $j}"; done  

$i im Beispiel“ verwirrt „awk welche verwendet werden soll (Shell oder eigene Variable – Vorrang), da beide mit dem Präfix $ bezeichnet werden.

note

Shell, die Standard für „portable“ Skripte ist, unterstützt nicht:

(( i=1; i<=3; i++; )) und <<< $var Konstrukte

Sie können auch den Befehl seq in for Schleife für eine feinere Steuerung bei der Generierung von Zahlenfolgen, falls verfügbar.

Kommentare

  • Ihre Schleife würde nur funktionieren, wenn zufällig drei Dateien aufgerufen würden , 2 und 3 im aktuellen Verzeichnis. Außerdem verwenden Sie die in der Shell nicht zitierte Variablenerweiterung, die unerwünschte Folgen haben kann, wenn die Daten Dateinamenmuster enthalten (z. B. *). Die echo kann die Daten außerdem ändern, wenn sie Backslashes enthält.

Antwort

#!/bin/sh var="data1,data2,data3" unset data while [ "$var" != "$data" ]; do data=${var%%,*} # delete first comma and the bit after it var=${var#*,} # delete bit up to first comma (and the comma) printf "data = "%s"\n" "$data" done 

Hier verwenden wir Variablensubstitutionen, um jedes aufeinanderfolgende durch Kommas getrennte Datenfeld aus dem Wert der Variablen var zu erhalten. Die erste Zuweisung zu data in der Schleife entfernt nach dem ersten Komma alles aus $var. Die Variable var wird dann so geändert, dass das erste Bit bis zum ersten Komma gelöscht wird.

Dies wird fortgesetzt, bis "$var" = "$data" was bedeutet, dass mit der Zeichenfolge nichts mehr getan werden kann.

Auf diese Weise können wir durch Kommas getrennte Datenzeichenfolgen verarbeiten, die eingebettete Zeilenumbrüche enthalten:

var="line1 line2,data2,last bit goes here" 

Mit den obigen Werten in var würde das obige Skript

data = "line1 line2" data = "data2" data = "last bit goes here" 

Keine Sorge um eingebettete Zeilenumbrüche; Sie müssen sehr selten Aufrufe von awk durchlaufen.

Beachten Sie, dass awk freut sich sehr, Ihre Zeichenfolge als eine Reihe von durch Kommas getrennten Feldern zu lesen und diese zu durchlaufen:

printf "%s\n" "$var" | awk -F "," "{ for (i=1; i<=NF; i++) print $i }" 

Mit var="data1,data2,data3", dies würde

data1 data2 data3 

eine andere Shell-Lösung drucken, die die Variable zum Aufteilen des $var -Werts in Bits, während set -f zum Deaktivieren der Dateinamenerweiterung verwendet wird:

set -f oldIFS=$IFS; IFS="," set -- $var IFS=$oldIFS; unset oldIFS set +f for data do printf "data = "%s"\n" "$data" done 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.