Wie analysiere ich jede Zeile einer Textdatei als Argument für einen Befehl?

Ich möchte ein Skript schreiben, das einen .txt -Dateinamen als Argument verwendet und die Dateizeile liest zeilenweise und übergibt jede Zeile an einen Befehl. Beispielsweise wird command --option "LINE 1", dann command --option "LINE 2" usw. ausgeführt. Die Ausgabe des Befehls wird in eine andere Datei geschrieben. Wie gehe ich vor? Ich weiß nicht, wo ich anfangen soll.

Antwort

Verwenden Sie die Schleife while read:

: > another_file ## Truncate file. while IFS= read -r LINE; do command --option "$LINE" >> another_file done < file 

Eine andere Möglichkeit besteht darin, die Ausgabe nach Block umzuleiten:

while IFS= read -r LINE; do command --option "$LINE" done < file > another_file 

Zuletzt wird die Datei geöffnet:

exec 4> another_file while IFS= read -r LINE; do command --option "$LINE" >&4 echo xyz ## Another optional command that sends output to stdout. done < file 

Wenn einer der Befehle Eingaben liest, wäre dies eine gute Sache Idee, ein anderes fd für die Eingabe zu verwenden, damit die Befehle es nicht essen (hier unter der Annahme ksh, zsh oder Verwenden Sie für -u 3 <&3 stattdessen portabel):

while IFS= read -ru 3 LINE; do ... done 3< file 

Fin Um Argumente zu akzeptieren, können Sie Folgendes tun:

#!/bin/bash FILE=$1 ANOTHER_FILE=$2 exec 4> "$ANOTHER_FILE" while IFS= read -ru 3 LINE; do command --option "$LINE" >&4 done 3< "$FILE" 

Welches könnte ausgeführt werden als:

bash script.sh file another_file 

Zusätzliche Idee. Verwenden Sie mit bash readarray:

readarray -t LINES < "$FILE" for LINE in "${LINES[@]}"; do ... done 

Hinweis: IFS= kann weggelassen werden, wenn es Ihnen nichts ausmacht, Zeilenwerte von führenden und nachfolgenden Leerzeichen zu trennen.

Antwort

Eine weitere Option ist xargs.

Mit GNU xargs:

xargs -a file -I{} -d"\n" command --option {} other args 

{} ist der Platzhalter für die Textzeile.

Andere xargs hat im Allgemeinen nicht -a, -d, aber einige haben -0 für NUL-begrenzte Eingabe. Mit diesen können Sie Folgendes tun:

< file tr "\n" "\0" | xargs -0 -I{} command --option {} other args 

Auf Unix-konformen Systemen (-I ist in POSIX optional und nur erforderlich für UNIX-konforme Systeme), müssen Sie die Eingabe vorverarbeiten, um die Zeilen in dem von xargs:

< file sed "s/"/"\\""/g;s/.*/"&"/" | xargs -E "" -I{} command --option {} other args 

Beachten Sie jedoch, dass einige xargs -Implementierungen eine sehr niedrige Grenze für die maximale Größe des Arguments haben (z. B. 255 unter Solaris). das in der Unix-Spezifikation zulässige Minimum).

Kommentare

  • reduzierbar auf <file xargs -L 1 -I{} command --option {} other args
  • @iruvar, nein, das würde Anführungszeichen verarbeiten und einige Leerzeichen entfernen.

Antwort

Genau halten zur Frage:

#!/bin/bash # xargs -n param sets how many lines from the input to send to the command # Call command once per line [[ -f $1 ]] && cat $1 | xargs -n1 command --option # Call command with 2 lines as args, such as an openvpn password file # [[ -f $1 ]] && cat $1 | xargs -n2 command --option # Call command with all lines as args # [[ -f $1 ]] && cat $1 | xargs command --option 

Kommentare

  • funktionierte wie Charme 🙂
  • +1 liebte dies, danke

Antwort

Die beste Antwort, die ich für und ist:

for i in `cat`; do "$cmd" "$i"; done < $file 

BEARBEITEN:

… vier Jahre später …

Nach mehreren Abstimmungen und etwas mehr Erfahrung würde ich jetzt Folgendes empfehlen:

xargs -l COMMAND < file 

Kommentare

  • Dadurch wird der Befehl einmal für jedes Wort in der Datei aufgerufen. Außerdem sollten Sie immer Verweise auf Shell-Variablen angeben (wie in do "$cmd" "$i";), es sei denn, Sie haben einen Grund, dies nicht zu tun. Wenn die Datei ein * als eigenständiges Wort enthalten würde, würde Ihr Code $cmd * ausführen, womit der Befehl natürlich ausgeführt würde eine Liste der Dateien im aktuellen Verzeichnis.
  • @ G-Man, außer in zsh, `cat` würde bereits die * erweitern (die nicht zitierte $i könnte noch einen Platzhalter (eine zweite Runde) erweitern, wenn die Erweiterung von `cat` stellt einige vor). In jedem Fall ist dieser Ansatz in der Tat falsch.
  • +1. Dies funktioniert einwandfrei, wenn jede Zeile nur die Eingabe enthält, die für den Befehl erforderlich ist, der ohne Leerzeichen verwendet wird.
  • +1, beliebte xargs-Lösung
  • Dies funktioniert! (die spätere Bearbeitung xargs -l COMMAND < file). Danke!

Antwort

 sed "s/"/"\\\\""/g;s/.*/\$* "&"/" <<\FILE |\ sh -s -- command echo --option all of the{&}se li$n\es "are safely shell quoted and handed to command as its last argument following --option, and, here, before that echo FILE 

AUSGABE

--option all of the{&}se li$n\es "are safely shell --option quoted and handed to command as its last argument --option following --option, and, here, before that echo 

Antwort

ed file.txt %g/^/s// / 2,$g/^/-,.j 1s/^/command/ wq chmod 755 file.txt ./file.txt 

Nehmen Sie alle Zeilen einer Datei und übergeben Sie sie als Argumente an einen einzelnen Befehl, z. B.

command line1 line2 line3 .... 

Wenn Sie die --option benötigen Flag vor jeder Zeile Ändern Sie den zweiten Befehl in:

%g/^/s// --option / 

Kommentare

  • Wofür -1 mit ed … wirklich?
  • Ich habe ‚ Sie nicht abgelehnt, aber die Person, die wahrscheinlich folgende Gründe hatte: (1) Das geht nicht was die Frage verlangt. Dadurch wird der Befehl einmal mit dem gesamten Inhalt der Datei in der Befehlszeile aufgerufen. anstatt einmal pro Zeile .(2) Dies hat nichts mit Zeichen zu tun, die für die Shell speziell sind (die sich möglicherweise in der Datei befinden). Beispiel: ', ", <, >, ; usw. (3) Dadurch wird eine unnötige temporäre Datei erstellt. (4) Solche Dinge werden in der Regel mit „hier Dokumenten“ gemacht. (5) Ihre Befehle ed sind ungeschickt. Die ersten beiden Befehle können auf %s/^/ / und %j reduziert werden.

Schreibe einen Kommentar

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