Jaki jest poprawny sposób wywołania polecenia przechowywanego w zmiennej?
Czy są jakieś różnice między 1 a 2?
#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"
#1
$cmd
#2
eval "$cmd"
shell
unix
parameter-expansion
Volodymyr Bezuglyy
źródło
źródło
Odpowiedzi:
Powłoki uniksowe wykonują serię transformacji na każdym wierszu wejścia przed ich wykonaniem. W przypadku większości powłok wygląda to mniej więcej tak (zaczerpnięte ze strony
bash
podręcznika):Użycie
$cmd
bezpośrednio powoduje zastąpienie go poleceniem podczas fazy rozwijania parametrów, a następnie przechodzi wszystkie kolejne transformacje.Użycie
eval "$cmd"
nic nie robi, aż do fazy usuwania cytatów, gdzie$cmd
zwracana jest taka, jaka jest i przekazywana jako parametr doeval
, którego funkcją jest ponowne uruchomienie całego łańcucha przed wykonaniem.Zasadniczo są one takie same w większości przypadków i różnią się, gdy twoje polecenie wykorzystuje kroki transformacji aż do rozwinięcia parametrów. Na przykład, używając rozwijania nawiasów:
$ cmd="echo foo{bar,baz}" $ $cmd foo{bar,baz} $ eval "$cmd" foobar foobaz
źródło
eval "$cmd"
bez pisaniaeval
?$($cmd)
?${$cmd}
?eval
operacja analizuje dane jako składnię; jest zatem bardzo wrażliwy na bezpieczeństwo, a robienie tego w sposób niejawny byłoby bardzo złą formą.Jeśli zrobisz to,
eval $cmd
gdy my to zrobimycmd="ls -l"
(interaktywnie i w skrypcie), uzyskamy pożądany efekt. W twoim przypadku masz potok z grep bez wzorca, więc część grep zakończy się niepowodzeniem z komunikatem o błędzie. Po prostu$cmd
wygeneruje komunikat „polecenie nie znaleziono” (lub coś podobnego). Więc spróbuj użyć eval i użyj gotowego polecenia, a nie takiego, które generuje komunikat o błędzie.źródło
$cmd
po prostu zamieni zmienną na jej wartość do wykonania w linii poleceń.eval "$cmd"
wykonuje rozwijanie zmiennych i podstawianie poleceń przed wykonaniem wynikowej wartości w wierszu poleceńDruga metoda jest pomocna, gdy chcesz uruchamiać polecenia, które nie są elastyczne, np.
for i in {$a..$b}
pętla formatu nie zadziała, ponieważ nie zezwala na zmienne.
W takim przypadku obejściem jest potok do bash lub eval.
Testowano na Mac OSX 10.6.8, Bash 3.2.48
źródło
Myślę, że powinieneś położyć
(lewy przycisk) symbole wokół zmiennej.
źródło