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 Befehleed
sind ungeschickt. Die ersten beiden Befehle können auf%s/^/ /
und%j
reduziert werden.