2011-01-12 14 views
52

Jaki jest poprawny sposób wywołania jakiegoś polecenia przechowywanego w zmiennej?
Czy są jakieś różnice między 1 a 2?Jak wykonać polecenie zapisane w zmiennej?

#!/bin/sh 
cmd="ls -la $APPROOTDIR | grep exception" 
#1 
$cmd 
#2 
eval "$cmd" 
+4

Zobacz [BashFAQ/050] (http://mywiki.wooledge.org/BashFAQ/050). –

Odpowiedz

67

Powłoki uniksowe wykonują serię przekształceń na każdym wierszu wejścia przed ich wykonaniem. Dla większości muszli wygląda mniej więcej tak (wzięte z bash podręcznika):

  • początkowe słowo łupania
  • rozwijanie nawiasów
  • tyldy
  • parametrów, zmiennych i wyrażeń arytmetycznych
  • polecenia podstawienie
  • podział słowa dodatkowego
  • ścieżka e Xpansion (aka globbing)
  • usunięcie cytatu

Korzystanie $cmd bezpośrednio zostaje ona zastąpiona przez polecenia w fazie ekspansji parametr, a następnie przechodzi wszystkie następujące transformacje.

Korzystanie eval "$cmd" nic nie robi aż fazie usuwania cytat, gdzie $cmd zwracany jest jak jest, i przekazany jako parametr do eval, którego funkcją jest ponownie uruchomić cały łańcuch przed wykonaniem.

Zasadniczo są one takie same w większości przypadków i różnią się, gdy polecenie używa kroków transformacji do rozszerzenia parametrów. Na przykład użycie rozszerzenia nawiasu klamrowego:

$ cmd="echo foo{bar,baz}" 
$ $cmd 
foo{bar,baz} 
$ eval "$cmd" 
foobar foobaz 
+5

Jak zrobić "eval" $ cmd "' bez pisania 'eval'?' $ ($ Cmd) '?' $ {$ Cmd} '? –

+2

@StevenLu, żaden z nich nie jest równoważny - celowo więc:' 'eval 'operacja analizuje dane jako składnię, dlatego jest bardzo wrażliwa na bezpieczeństwo, a wykonywanie jej w sposób niejawny byłoby bardzo złą formą. –

-2

myślę yu umieścić `symbole wokół zmiennej (jednego z ~ jeśli Shift wciśnięty)

+3

Spowoduje to uruchomienie wyjścia polecenia, które np. w przypadku ls -l wygeneruje komunikat taki jak "total" polecenie nie znaleziono "(ponieważ total ... jest częścią wyjścia ls -l, np.) Więc to nie jest to, czego chcesz. –

3

Jeśli po prostu zrobić eval $cmd gdy robimy cmd="ls -l" (interaktywnie iw skrypcie) otrzymujemy pożądany rezultat. 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 "nie znaleziono polecenia" (lub tego typu). Więc spróbuj użyć eval i użyj zakończonego polecenia, a nie takiego, który generuje komunikat o błędzie.

+0

To był tylko błąd drukarski Powinien być "wyjątek grep" –

+0

następnie użyć eval, a nie $ cmd przez siebie, ponieważ prawdopodobnie nie będzie działać (nie w moich testach, pod bash i zsh) .Jest to, co eval miał zrobić ... –

Powiązane problemy