Was ist der richtige Weg, um einen in einer Variable gespeicherten Befehl aufzurufen?
Gibt es Unterschiede zwischen 1 und 2?
#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"
#1
$cmd
#2
eval "$cmd"
Was ist der richtige Weg, um einen in einer Variable gespeicherten Befehl aufzurufen?
Gibt es Unterschiede zwischen 1 und 2?
#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"
#1
$cmd
#2
eval "$cmd"
Antworten:
Unix-Shells führen eine Reihe von Transformationen in jeder Eingabezeile durch, bevor sie ausgeführt werden. Für die meisten Shells sieht es ungefähr so aus (aus der bash
Manpage entnommen ):
Durch die $cmd
direkte Verwendung wird es während der Parametererweiterungsphase durch Ihren Befehl ersetzt und anschließend allen folgenden Transformationen unterzogen.
Mit using eval "$cmd"
wird nichts unternommen, bis die Phase zum Entfernen des Anführungszeichens unverändert $cmd
zurückgegeben und als Parameter an übergeben wird eval
, dessen Funktion darin besteht, die gesamte Kette vor der Ausführung erneut auszuführen.
Im Grunde sind sie in den meisten Fällen gleich und unterscheiden sich, wenn Ihr Befehl die Transformationsschritte bis zur Parametererweiterung verwendet. Beispiel: Verwenden der Klammererweiterung:
$ cmd="echo foo{bar,baz}"
$ $cmd
foo{bar,baz}
$ eval "$cmd"
foobar foobaz
eval "$cmd"
ohne zu schreiben eval
? $($cmd)
? ${$cmd}
?
eval
Operation analysiert Daten als Syntax; Es ist daher sehr sicherheitsrelevant, und es implizit zu tun, wäre eine sehr schlechte Form.
Wenn Sie nur tun , eval $cmd
wenn wir das tun cmd="ls -l"
(interaktiv und in einem Skript) wir das gewünschte Ergebnis erhalten. In Ihrem Fall haben Sie eine Pipe mit einem Grep ohne Muster, sodass der Grep-Teil mit einer Fehlermeldung fehlschlägt. Nur $cmd
wird eine "Befehl nicht gefunden" (oder eine solche) Nachricht generiert. Versuchen Sie also, eval zu verwenden, und verwenden Sie einen fertigen Befehl, der keine Fehlermeldung generiert.
$cmd
würde nur die Variable durch ihren Wert ersetzen, der in der Befehlszeile ausgeführt werden soll.
eval "$cmd"
Führt eine Variablenerweiterung und Befehlssubstitution durch, bevor der resultierende Wert in der Befehlszeile ausgeführt wird
Die zweite Methode ist hilfreich, wenn Sie Befehle ausführen möchten, die nicht flexibel sind, z.
for i in {$a..$b}
Die Formatschleife funktioniert nicht, da sie keine Variablen zulässt.
In diesem Fall ist eine Pipe zum Bash oder Eval eine Problemumgehung.
Getestet unter Mac OSX 10.6.8, Bash 3.2.48
Ich denke du solltest sagen
`
(Backtick) Symbole um Ihre Variable.