Ich möchte einen Befehl speichern, der zu einem späteren Zeitpunkt in einer Variablen verwendet werden soll (nicht die Ausgabe des Befehls, sondern den Befehl selbst).
Ich habe ein einfaches Skript wie folgt:
command="ls";
echo "Command: $command"; #Output is: Command: ls
b=`$command`;
echo $b; #Output is: public_html REV test... (command worked successfully)
Wenn ich jedoch etwas Komplizierteres versuche, schlägt dies fehl. Zum Beispiel, wenn ich mache
command="ls | grep -c '^'";
Die Ausgabe ist:
Command: ls | grep -c '^'
ls: cannot access |: No such file or directory
ls: cannot access grep: No such file or directory
ls: cannot access '^': No such file or directory
Haben Sie eine Idee, wie ich einen solchen Befehl (mit Pipes / mehreren Befehlen) zur späteren Verwendung in einer Variablen speichern könnte?
Antworten:
Verwenden Sie eval:
quelle
backticks
. y = $ (eval $ x) mywiki.wooledge.org/BashFAQ/082eval
Dies ist nur dann akzeptabel, wenn Sie dem Inhalt Ihrer Variablen vertrauen. Wenn Sie beispielsweisex="ls $name | wc"
(oder sogarx="ls '$name' | wc"
) ausgeführt werden, ist dieser Code ein schneller Weg, um Sicherheitsanfälligkeiten bezüglich Injection oder Eskalation von Berechtigungen zu beheben, wenn diese Variable von jemandem mit weniger Berechtigungen festgelegt werden kann. (Durchlaufen Sie beispielsweise alle Unterverzeichnisse in/tmp
? Sie sollten jedem einzelnen Benutzer im System vertrauen, dass er keinen anruft .$'/tmp/evil-$(rm -rf $HOME)\'$(rm -rf $HOME)\'/'
)eval
ist ein riesiger Fehlermagnet, der niemals ohne Warnung vor dem Risiko eines unerwarteten Analyseverhaltens empfohlen werden sollte (auch ohne böswillige Zeichenfolgen, wie im Beispiel von @ CharlesDuffy). Versuchen Sie es zum Beispielx='echo $(( 6 * 7 ))'
und danneval $x
. Sie könnten erwarten, dass "42" gedruckt wird, aber wahrscheinlich nicht. Können Sie erklären, warum es nicht funktioniert? Können Sie erklären, warum ich "wahrscheinlich" gesagt habe? Wenn die Antworten auf diese Fragen für Sie nicht offensichtlich sind, sollten Sie sie niemals berühreneval
.set -x
vorher, die ausgeführten Befehle zu protokollieren, damit Sie leichter sehen können, was passiert.Sie nicht verwenden
eval
! Es besteht ein großes Risiko, dass eine willkürliche Codeausführung eingeführt wird.BashFAQ-50 - Ich versuche, einen Befehl in eine Variable einzufügen , aber die komplexen Fälle schlagen immer fehl.
Legen Sie es in einem Array und erweitern , um alle Wörter mit doppelten Anführungszeichen
"${arr[@]}"
zu nicht der LETIFS
Spaltung aufgrund der Worte Wort Splitting .und sehen Sie den Inhalt des Arrays im Inneren. Mit
declare -p
können Sie den Inhalt des Arrays mit jedem Befehlsparameter in separaten Indizes anzeigen. Wenn ein solches Argument Leerzeichen enthält, wird durch Anführungszeichen beim Hinzufügen zum Array verhindert, dass es aufgrund von Word-Splitting aufgeteilt wird.und führen Sie die Befehle als aus
(oder) insgesamt eine
bash
Funktion verwenden, um den Befehl auszuführen,und rufen Sie die Funktion als gerecht auf
POSIX
sh
hat keine Arrays. Sie können also am ehesten eine Liste von Elementen in den Positionsparametern erstellen. Hier ist eine POSIX-sh
Methode zum Ausführen eines Mail-ProgrammsBeachten Sie, dass dieser Ansatz nur einfache Befehle ohne Umleitungen verarbeiten kann. Es kann keine Umleitungen, Pipelines, for / while-Schleifen, if-Anweisungen usw. Behandeln
Ein weiterer häufiger Anwendungsfall ist die Ausführung
curl
mit mehreren Headerfeldern und Nutzdaten. Sie können jederzeit Argumente wie unten definieren undcurl
den erweiterten Array-Inhalt aufrufenEin anderes Beispiel,
Nachdem die Variablen definiert sind, verwenden Sie ein Array, um Ihre Befehlsargumente zu speichern
und jetzt machen Sie eine richtig zitierte Erweiterung
quelle
Command=('echo aaa | grep a')
und"${Command[@]}"
in der Hoffnung, dass es buchstäblich den Befehl ausführtecho aaa | grep a
. Das tut es nicht. Ich frage mich, ob es einen sicheren Weg zum Ersetzen gibteval
, aber es scheint, dass jede Lösung die gleiche Kraft hat, dieeval
gefährlich sein könnte. Ist es nicht?Command() { echo aaa | grep a; }
- Danach können Sie einfachCommand
oderresult=$(Command)
oder dergleichen ausführen .Mit dieser Methode wird der Befehl sofort ausgewertet und sein Rückgabewert gespeichert.
Gleiches gilt für den Backtick
Wenn Sie eval in the verwenden,
$(...)
wird es später nicht ausgewertetMit eval wird ausgewertet, wann
eval
es verwendet wirdWenn Sie im obigen Beispiel einen Befehl mit Argumenten ausführen müssen, fügen Sie diese in die Zeichenfolge ein, die Sie speichern
Für Bash-Skripte ist dies selten relevant, aber eine letzte Anmerkung. Sei vorsichtig mit
eval
. Eval nur Zeichenfolgen, die Sie steuern, niemals Zeichenfolgen, die von einem nicht vertrauenswürdigen Benutzer stammen oder aus nicht vertrauenswürdigen Benutzereingaben erstellt wurden.quelle
eval $stored_date
dies in Ordnung sein kann, wenn esstored_date
nur enthältdate
, abereval "$stored_date"
viel zuverlässiger ist. Führen Sie ein Beispielstr=$'printf \' * %s\\n\' *'; eval "$str"
mit und ohne Anführungszeichen um das Finale"$str"
aus. :)Speichern Sie Ihren Befehl für Bash wie folgt:
Führen Sie Ihren Befehl folgendermaßen aus:
quelle
Ich habe verschiedene Methoden ausprobiert:
Ausgabe:
Wie Sie sehen können,
"$@"
lieferte nur der dritte das richtige Ergebnis.quelle
Seien Sie vorsichtig bei der Registrierung einer Bestellung mit:
X=$(Command)
Dieser wird noch ausgeführt, noch bevor er aufgerufen wird. Um dies zu überprüfen und zu bestätigen, müssen Sie Folgendes tun:
quelle
quelle
Es ist nicht erforderlich, Befehle in Variablen zu speichern, auch wenn Sie sie später verwenden müssen. Führen Sie es einfach wie gewohnt aus. Wenn Sie in einer Variablen speichern, benötigen Sie eine
eval
Anweisung oder rufen einen unnötigen Shell-Prozess auf, um "Ihre Variable auszuführen".quelle
var='*.txt'; find . -name "$var"