it-swarm.com.de

Wie wird die Ausgabe eines Befehls in der aktuellen Shell ausgeführt?

Ich kenne das Dienstprogramm source (aka .), mit dem der Inhalt einer Datei abgerufen und in der aktuellen Shell ausgeführt wird.

Jetzt verwandle ich etwas Text in Shell-Befehle und führe sie dann wie folgt aus:

$ ls | sed ... | sh

ls ist nur ein zufälliges Beispiel, der ursprüngliche Text kann alles sein. Auch sed, nur ein Beispiel für die Transformation von Text. Das interessante Bit ist sh. Ich pfeife alles was ich zu sh bekam und es läuft.

Mein Problem ist, dass Sie eine neue Sub-Shell starten. Ich möchte die Befehle lieber in meiner aktuellen Shell ausführen. Wie ich es mit source some-file machen könnte, wenn ich die Befehle in einer Textdatei hätte.

Ich möchte keine temporäre Datei erstellen, weil sie sich schmutzig anfühlt.

Alternativ möchte ich meine Sub-Shell mit den gleichen Eigenschaften wie meine aktuelle Shell starten.

aktualisieren

Ok, die Lösungen mit Backtick funktionieren sicherlich, aber ich muss das oft tun, während ich die Ausgabe überprüfe und ändere. Daher würde ich es sehr bevorzugen, wenn ich am Ende eine Möglichkeit hätte, das Ergebnis in etwas zu lenken.

trauriges Update

Ah, das /dev/stdin-Ding sah so hübsch aus, aber in einem komplexeren Fall funktionierte es nicht.

Also habe ich folgendes:

find . -type f -iname '*.doc' | ack -v '\.doc$' | Perl -pe 's/^((.*)\.doc)$/git mv -f $1 $2.doc/i' | source /dev/stdin

Dadurch wird sichergestellt, dass für alle .doc-Dateien die Erweiterung niedriger ist.

Und was übrigens mit xargs gehandhabt werden kann, aber das ist nicht der Punkt.

find . -type f -iname '*.doc' | ack -v '\.doc$' | Perl -pe 's/^((.*)\.doc)$/$1 $2.doc/i' | xargs -L1 git mv

Wenn ich den ersteren laufe, wird er sofort beendet, es passiert nichts.

73
kch
$ ls | sed ... | source /dev/stdin

UPDATE: Dies funktioniert in bash 4.0 sowie tcsh und dash (wenn Sie source in . ändern). Anscheinend war dies in bash 3.2 fehlerhaft. Aus den Versionshinweisen zu bash 4.0 :

Ein Fehler wurde behoben, der `. ' das Lesen und Ausführen von Befehlen aus nicht regulären Dateien wie Geräten oder Named Pipes ist fehlgeschlagen.

76
mark4o

Der Befehl eval existiert zu diesem Zweck.

eval "$( ls | sed... )"

Mehr aus dem bash Handbuch :

eval

          eval [arguments]

Die Argumente werden miteinander verkettet in einen einzigen Befehl, der wird dann gelesen und ausgeführt, und sein Der Exit-Status wurde als Exit zurückgegeben. Status der Eval. Wenn es keine .__ gibt. Argumente oder nur leere Argumente, die Rückkehrstatus ist Null.

113
Juliano

Wow, ich weiß, das ist eine alte Frage, aber ich habe in letzter Zeit genau das gleiche Problem gefunden (so bin ich hierher gekommen).

Wie auch immer - ich mag die source /dev/stdin-Antwort nicht, aber ich glaube, ich habe eine bessere gefunden. Es ist tatsächlich täuschend einfach:

echo ls -la | xargs xargs

Schön, richtig? Eigentlich tut dies immer noch nicht das, was Sie wollen, denn wenn Sie mehrere Zeilen haben, werden diese zu einem einzigen Befehl zusammengefasst, anstatt jeden Befehl einzeln auszuführen. Die Lösung, die ich gefunden habe, ist:

ls | ... | xargs -L 1 xargs

die Option -L 1 bedeutet, dass Sie höchstens eine Zeile pro Befehlsausführung verwenden. Hinweis: Wenn Ihre Zeile mit einem abschließenden Leerzeichen endet, wird sie mit der nächsten Zeile verkettet! Stellen Sie also sicher, dass jede Zeile mit einem Leerzeichen endet.

Schließlich können Sie tun 

ls | ... | xargs -L 1 xargs -t

um zu sehen, welche Befehle ausgeführt werden (-t ist ausführlich).

Hoffe, jemand liest das!

32
rabensky

Versuchen Sie es mit Prozessersetzung , wodurch die Ausgabe eines Befehls durch eine temporäre Datei ersetzt wird, die dann bezogen werden kann:

source <(echo id)
26
rishta

Ich glaube, das ist "die richtige Antwort" auf die Frage:

ls | sed ... | while read line; do $line; done

Das heißt, man kann in eine while-Schleife leiten; Der Befehl read nimmt eine Zeile von seiner stdin und weist sie der Variablen $line zu. $line wird dann zum Befehl, der innerhalb der Schleife ausgeführt wird. und es fährt fort, bis in seiner Eingabe keine weiteren Zeilen vorhanden sind.

Mit einigen Kontrollstrukturen (wie einer anderen Schleife) funktioniert das immer noch nicht, aber in diesem Fall passt es zur Rechnung.

6
Geoff Nixon
`ls | sed ...`

Ich habe das Gefühl, ls | sed ... | source - wäre hübscher, aber leider versteht source nicht, dass -stdin bedeutet.

5
chaos

Ich denke, Ihre Lösung ist die Befehlsersetzung mit Backticks: http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html

Siehe Abschnitt 3.4.5

1
Eric Wendelin

Um die Lösung von mark4o auf bash 3.2 (macos) zu verwenden, kann ein Here-String anstelle von Pipelines wie in diesem Beispiel verwendet werden:

. /dev/stdin <<< "$(grep '^alias' ~/.profile)"
0
ish-west

Warum nicht source verwenden?

$ ls | sed ... > out.sh ; source out.sh
0
Kaleb Pederson