Ich habe eine Datei.txt mit einem in einer Zeile gespeicherten Befehl (dieser Befehl ist gültig, wenn er in der Konsole ausgeführt wird) und ich möchte ihn in einer Zeile mit sh ausführen, wie
cat file.txt | eval
was fehlt? irgendwelche Profi-Tipps?
und was ist, wenn ich eine Datei mit vielen Befehlen habe (einen für jede Zeile) und nur einen Befehl (eine ganze Zeile) ausführen möchte? Meine erste Idee ist:
head -n5 | tail -n1 | eval
Antwort1
eval
liest seine Befehlszeichenfolge nicht von stdin.
eval "$(cat file.txt)"
# or easier, in ksh/bash/zsh
eval "$(<file.txt)"
# usually you cannot be sure that a command ends at the end of line 5
eval "$(head -n 5 file.txt)"
Stattdessen können Sie Standard- oder / / eval
verwenden, wenn sich die Befehle sowieso in einer Datei befinden:.
bash
zsh
ksh
source
source ./file
(Beachten Sie, dass es wichtig ist, hinzuzufügen, dass ./
. Andernfalls wird nach in source
gesucht , bevor das im aktuellen Verzeichnis berücksichtigt wird. Im POSIX-Modus würde das im aktuellen Verzeichnis nicht einmal berücksichtigt , selbst wenn es nicht in gefunden würde .)file
$PATH
file
bash
file
$PATH
Das funktioniert natürlich nicht, wenn man einen Teil der Datei auswählt. Das könnte man folgendermaßen machen:
head -n 5 file.txt >commands.tmp
source ./commands.tmp
Oder (mit ksh93, zsh, bash):
source <(head -n 5 file.txt)
Antwort2
also … eine Lösung Ihrer Frage ist zu 100 % möglich und (im Kontext von make
) wichtig.
Ich bin bei einem Makefile auf dieses Problem gestoßen und angesichts der Schwierigkeit, Bash-Befehle in einem Makefile zu verschachteln, das bereits $(...)
Variablen aufruft, ist es schön, genau das tun zu können, wonach Sie gefragt haben.
Anstatt zu verwenden eval
, verwenden Sie einfach den Systembefehl von awk
oder :perl
// command_list.sh:
echo "1"
echo "2"
echo "3"
// command line prompt:
$: cat command_list.sh | awk '{system($0)}'
1
2
3
Und Kommandoaufbau:
// a readable version--rather than building up an awk miniprogram,
// split into logical blocks:
$: cat inputs.txt | awk '{print "building "$1" command "$2" here "}' | awk '{system($0)}'
Antwort3
Technisch ist es unmöglich, etwas in Ihrer aktuellen Umgebung auszuwerten, wenn Sie es aus einer Pipe lesen möchten, da jeder Befehl in der Pipeline als separater Prozess ausgeführt wird.
Je nachdem, was Sie erreichen möchten, spielt das jedoch möglicherweise keine Rolle. In jedem Fall wird hier eval
der Inhalt einer Pipe ausgeführt:
❯ echo echo hi | eval "$(cat -)"
hi
Hier ist ein Beispiel für den Haken. Etwas wie das Folgende wird nicht gedruckt 1
:
❯ echo a=1 | eval "$(cat -)"; echo $a
Wir müssten stattdessen Folgendes tun:
❯ echo a=1 | { eval "$(cat -)"; echo $a; }
1
Antwort4
Wenn Sie nicht unbedingt verwenden möchten eval
, verwenden Sie sh
:
cat file.txt | sh
Ja, es wird in einer separaten SH-Instanz ausgeführt, aber diese Tatsache ist selbstdokumentiert.
Und außerdem gibt es while read
:
cat file.txt | while read cmd; do eval $cmd; done
So führen Sie den Befehl in der 5. Zeile von file.txt aus:
sed -n 5p file.txt | sh
(Mir ist klar, dass das eine alte Frage ist.)