Analysieren einer durch Trennzeichen getrennten Textdatei in Bash als Befehlsargumente

10

Ich habe eine Textdatei wie folgt aufgeteilt:

field1,field2,field3 
xield1,xield2,xield3 
dield1,dield2,dield3 
gield1,gield2,gield3

Jede dieser Spalten ist ein Parameter für ein Programm, und ich möchte, dass das Programm für jede Zeile aufgerufen wird

Ich hatte auf eine Schleife gehofft, so etwas wie:

for $i in file
    command $field2 -x $field3 -PN -$field1 >> output
done

Was wäre der beste Weg, um so etwas in Bash zu erreichen?

Dean
quelle
Ist die Anzahl der Felder konstant?
Joseph R.
@ JosephR. Ja, das sind sie, immer 3
Dean

Antworten:

7
while IFS=, read xx yy zz;do
    echo $xx $yy $zz
done < input_file

Dies sollte funktionieren, wenn die Anzahl der Felder konstant ist. Anstatt echoIhren Befehl zu verwenden.

Kaffeetasse
quelle
Danke, ich habe es nur versucht, aber es scheint nur für die erste Zeile zu funktionieren. Sobald ein Befehl erfolgreich ist, versucht er nicht den nächsten, wenn er fehlschlägt, versucht er den nächsten ...
Dean
Wie meinst du Erfolg oder Misserfolg? Was macht dein Befehl?
Kaffee Tasse
Ich würde vermuten, dass der Befehl, den er ausführt, die Standardeingabe liest, bevor der Befehl "Lesen" darauf zugreifen kann.
Plugwash
4

Sie sollten ein whilemit dem readeingebauten verwenden:

while IFS= read -r line;do
    fields=($(printf "%s" "$line"|cut -d',' --output-delimiter=' ' -f1-))
    command "${fields[1]}" -x "${fields[2]}" ... # ${fields[1]} is field 2
done < your_file_here

Wie das funktioniert

  • Die cutAnweisung nimmt die Zeile und teilt sie in das durch angegebene Trennzeichen auf -d.
  • Das --output-delimiterist das Trennzeichen, cutmit dem die ausgewählten Felder angezeigt werden. Hier wählen wir ein Leerzeichen aus, damit wir die verschiedenen Felder in das Array einfügen können fields.
  • Schließlich wollen wir alle Felder (von Feld 1 bis zum Ende) und hier -f1-kommt das ins Spiel.
  • Jetzt haben Sie die verschiedene Felder in dem Array - Variable gespeichert fields, können Sie ein bestimmtes Feld , das Sie mit der Syntax wollen zugreifen , ${field[number]}wo numberman weniger ist als die tatsächliche Feldnummer , die Sie da Array - Indizierung wollen nullbasiert ist in Bash.

Hinweis

  • Dies schlägt fehl, wenn eines Ihrer Felder Leerzeichen enthält.

Für eine konstante Anzahl von Feldern

Sie können stattdessen etwas Ähnliches wie die Antwort von 1_CR tun :

while IFS= read -r line;do
    IFS=, read -r field1 field2 field3 <<-EOI
    $line
    EOI
    command "$field2" -x "$field3" ... 
done < your_file_here

Das Obige scheint zwar lauter zu sein, sollte aber in jeder POSIX-kompatiblen Shell funktionieren, nicht nur in Bash.

Joseph R.
quelle
Es liest nicht die Datei ein, mit der ich Probleme habe, sondern teilt die Zeile in Spalten auf.
Dean
@ Dean Ja, sorry. Ich habe nicht aufgepasst. Daran arbeiten wir jetzt.
Joseph R.
@ Dean Bitte beachten Sie die aktualisierte Antwort. Ich werde in Kürze eine Erklärung hinzufügen.
Joseph R.
@JosephR., Es ist möglich, die Verwendung externer Tools für die Aufteilung zu vermeiden, indem IFSim readAufruf ein geeigneter Wert festgelegt wird
iruvar
@ 1_CR Ich weiß, danke. Ich war gerade dabei :)
Joseph R.
1

Sie können readjede Zeile in ein Array aufteilen, ,indem Sie sie IFSentsprechend einstellen .

while IFS=, read -r -a input; do
 printf "%s\n" "${input[0]}" "${input[1]}"
done < input.txt

Im obigen Beispiel können Sie also über seinen Index auf jedes Array-Element zugreifen, beginnend mit 0.

iruvar
quelle
1

Dieser awkEinzeiler macht, was Sie wollen:

awk -F, '{cmd="echo " $2 " -x " $3 " -PN " $1 ">> output";  system(cmd)}' f.txt

Ersetzen Sie echodurch Ihren Befehl und f.txtdurch die Datei, die Sie durchlaufen möchten.

Kurze Erklärung: -F,Wird ,als Trennzeichen festgelegt. cmderstellt den Befehl und system(cmd)ruft den Befehl auf.

mkc
quelle
1

gnu sed kann ebenfalls verwendet werden.

sed infile -e 's!^\([^,]*\),\([^,]*\),\([^,]*\)$!command \1 -x \2 -PN \3!e' >> output

Beachten Sie die Verwendung der Option e für den Befehl s

hildred
quelle