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"
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"
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 do eval
, 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
eval "$cmd"
bez pisania eval
? $($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 zrobimy cmd="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.
$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
Myślę, że powinieneś położyć
`
(lewy przycisk) symbole wokół zmiennej.