eval mit Pipe-Befehl verwendet

eval mit Pipe-Befehl verwendet

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

evalliest 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 / / evalverwenden, wenn sich die Befehle sowieso in einer Datei befinden:.bashzshksh source

source ./file

(Beachten Sie, dass es wichtig ist, hinzuzufügen, dass ./. Andernfalls wird nach in sourcegesucht , 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$PATHfilebashfile$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 awkoder :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 evalder 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.)

verwandte Informationen