Angenommen, ich habe eine Datei foo.txt
mit N
Argumenten
arg1
arg2
...
argN
was ich an den Befehl übergeben muss my_command
Wie verwende ich die Zeilen einer Datei als Argumente eines Befehls?
Angenommen, ich habe eine Datei foo.txt
mit N
Argumenten
arg1
arg2
...
argN
was ich an den Befehl übergeben muss my_command
Wie verwende ich die Zeilen einer Datei als Argumente eines Befehls?
Antworten:
Wenn Ihre Shell (unter anderem) bash ist, ist eine Verknüpfung für
$(cat afile)
is$(< afile)
, also würden Sie schreiben:Dokumentiert in der Bash-Manpage im Abschnitt 'Befehlsersetzung'.
Lassen Sie Ihren Befehl alternativ von stdin lesen, also:
mycommand < file.txt
quelle
<
Operator zu verwenden. Dies bedeutet, dass die Shell selbst die Umleitung ausführt, anstatt diecat
Binärdatei für ihre Umleitungseigenschaften auszuführen ."$(…)"
, der Inhalt vonfile.txt
an die Standardeingabe von übergeben würdemycommand
, nicht als Argument."$(…)"
bedeutet , den Befehl auszuführen und die Ausgabe als Zeichenfolge zurückzugeben ; hier liest der "Befehl" nur die Datei, aber es könnte komplexer sein.Wie bereits erwähnt, können Sie die Backticks oder verwenden
$(cat filename)
.Was nicht erwähnt wurde, und ich denke, es ist wichtig anzumerken, ist, dass Sie sich daran erinnern müssen, dass die Shell den Inhalt dieser Datei nach Leerzeichen aufteilt und jedes "Wort", das sie findet, Ihrem Befehl als Argument gibt. Und obwohl Sie möglicherweise ein Befehlszeilenargument in Anführungszeichen setzen können, damit es Leerzeichen, Escape-Sequenzen usw. enthält, funktioniert das Lesen aus der Datei nicht dasselbe. Zum Beispiel, wenn Ihre Datei enthält:
Die Argumente, die Sie erhalten, sind:
Wenn Sie jede Zeile als Argument ziehen möchten, verwenden Sie das Konstrukt while / read / do:
quelle
read -r
es sei denn, Sie möchten Backslash-Escape-Sequenzen erweitern - und NUL ist ein sicherer Trennzeichen als die Newline, insbesondere wenn es sich bei den übergebenen Argumenten um Dateinamen handelt, die wörtliche Newlines enthalten können. Ohne IFS zu löschen, werden implizit führende und nachfolgende Leerzeichen gelöschti
.Übergibt den Dateiinhalt an den Befehl auf stdin, entfernt jedoch Zeilenumbrüche, sodass Sie nicht jede Zeile einzeln durchlaufen können. Dafür könnten Sie ein Skript mit einer 'for'-Schleife schreiben:
Oder (die mehrzeilige Variante):
Oder (mehrzeilige Variante mit
$()
statt``
):Verweise:
quelle
< file
Einfügen von Backticks bedeutet auch, dass überhaupt keine Umleitung durchgeführt wirdcommand
.command `< file`
weder in Bash noch in POSIX sh; zsh ist eine andere Sache, aber das ist nicht die Shell, um die es in dieser Frage geht).Hello World
eine Zeile. Sie werden sehen , es zuerst ausgeführtsome_command Hello
, dannsome_command World
, nichtsome_command "Hello World"
odersome_command Hello World
.Sie tun dies mit Backticks:
quelle
echo "Hello * Starry * World" > file.txt
im ersten Schritt, Sie mindestens vier separate Argumente auf den zweiten Befehl übergeben bekommen würde - und wahrscheinlich mehr, da das*
s auf die Namen der Dateien erweitert würde, die im aktuellen Verzeichnis vorhanden sind.fork()
löst tatsächlich eine Unterschale mit einem an seine Standardausgabe angehängten FIFO aus, ruft dann/bin/cat
als untergeordnetes Element dieser Unterschale auf und liest dann die Ausgabe durch das FIFO; Vergleichen Sie mit$(<file.txt)
, wodurch der Inhalt der Datei direkt in Bash gelesen wird, ohne dass Subshells oder FIFOs beteiligt sind.Wenn Sie dies auf robuste Weise tun möchten, die für jedes mögliche Befehlszeilenargument funktioniert (Werte mit Leerzeichen, Werte mit Zeilenumbrüchen, Werte mit wörtlichen Anführungszeichen, nicht druckbare Werte, Werte mit Glob-Zeichen usw.), wird es etwas interessanter.
So schreiben Sie in eine Datei mit einer Reihe von Argumenten:
... ersetzen
"argument one"
,"argument two"
usw. als angemessen.So lesen Sie aus dieser Datei und verwenden ihren Inhalt (in bash, ksh93 oder einer anderen aktuellen Shell mit Arrays):
Um aus dieser Datei zu lesen und ihren Inhalt zu verwenden (in einer Shell ohne Arrays; beachten Sie, dass dies Ihre lokale Befehlszeilenargumentliste überschreibt und daher am besten innerhalb einer Funktion ausgeführt wird, sodass Sie die Argumente der Funktion überschreiben und nicht die globale Liste):
Beachten Sie, dass
-d
(die Verwendung eines anderen Zeilenende-Trennzeichens) eine Nicht-POSIX-Erweiterung ist und eine Shell ohne Arrays diese möglicherweise auch nicht unterstützt. In diesem Fall müssen Sie möglicherweise eine Nicht-Shell-Sprache verwenden, um den durch NUL getrennten Inhalt in eineeval
sichere Form umzuwandeln:quelle
So übergebe ich den Inhalt einer Datei als Argument an einen Befehl:
quelle
$(<bar.txt)
(bei Verwendung einer Shell wie Bash mit der entsprechenden Erweiterung).$(<foo)
ist ein Sonderfall: Im Gegensatz zur regulären Befehlssubstitution, wie sie in verwendet wird$(cat ...)
, wird eine Subshell nicht für den Betrieb freigegeben und somit ein hoher Overhead vermieden.Wenn Sie nur eine Datei
arguments.txt
mit Inhalten drehen müssenin
my_command arg1 arg2 argN
dann können Sie einfach verwendenxargs
:Sie können dem
xargs
Aufruf zusätzliche statische Argumente hinzufügen, wiexargs -a arguments.txt my_command staticArg
sie aufgerufen werdenmy_command staticArg arg1 arg2 argN
quelle
In meiner Bash-Shell funktionierte Folgendes wie ein Zauber:
wo input_file ist
Auf diese Weise können Sie mit jeder Zeile aus input_file mehrere Befehle ausführen, ein netter kleiner Trick, den ich hier gelernt habe .
quelle
$(somecommand)
, wird dieser Befehl ausgeführt und nicht als Text weitergegeben. Ebenso>/etc/passwd
wird als Umleitung verarbeitet und überschrieben/etc/passwd
(wenn mit entsprechenden Berechtigungen ausgeführt) usw.xargs -d $'\n' sh -c 'for arg; do command1 "$arg"; command2 "arg"; command3 "arg"; done' _
- und auch effizienter, da so viele Argumente wie möglich an jede Shell übergeben werden, anstatt eine Shell pro Zeile in Ihrer Eingabedatei zu starten.cat
Nachdem ich die Antwort von @Wesley Rice ein paar Mal bearbeitet hatte, entschied ich, dass meine Änderungen einfach zu groß wurden, um seine Antwort weiter zu ändern, anstatt meine eigene zu schreiben. Also habe ich beschlossen, dass ich meine eigenen schreiben muss!
Lesen Sie jede Zeile einer Datei ein und bearbeiten Sie sie zeilenweise wie folgt:
Dies kommt direkt vom Autor Vivek Gite hier: https://www.cyberciti.biz/faq/unix-howto-read-line-by-line-from-file/ . Er bekommt den Kredit!
Und nun, um diese jetzt geschlossene Frage zu beantworten, die ich auch hatte: Ist es möglich, eine Liste von Dateien aus einer Datei hinzuzufügen? - Hier ist meine Antwort:
Beachten Sie, dass dies
FILES_STAGED
eine Variable ist, die den absoluten Pfad zu einer Datei enthält, die eine Reihe von Zeilen enthält, wobei jede Zeile ein relativer Pfad zu einer Datei ist, für die ich etwas tun möchtegit add
. Dieses Code-Snippet wird bald Teil der Datei "eRCaGuy_dotfiles / nützliche_skripte / sync_git_repo_to_build_machine.sh" in diesem Projekt, um die einfache Synchronisierung von Dateien in der Entwicklung von einem PC ( z. B. einem Computer, auf dem ich codiere) auf einen anderen ( z. B. a) zu ermöglichen leistungsstärkerer Computer, auf dem ich aufbaue): https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles .Verweise:
Verbunden:
git add
ihn aus: Ist es möglich, eine Liste von Dateien aus einer Datei hinzuzufügen?quelle