Czytałem skrypt bash, który ktoś stworzył i zauważyłem, że autor nie używa eval do oceny zmiennej jako polecenia
Autor użył
bash -c "$1"
zamiast
eval "$1"
Zakładam, że używanie eval jest preferowaną metodą i prawdopodobnie i tak jest szybsze. Czy to prawda?
Czy jest jakaś praktyczna różnica między nimi? Jakie są zauważalne różnice między nimi?
bash
shell-script
bash-script
kim jestem
źródło
źródło
e='echo foo'; $e
działa dobrze.Odpowiedzi:
eval "$1"
wykonuje polecenie w bieżącym skrypcie. Może ustawiać i używać zmiennych powłoki z bieżącego skryptu, ustawiać zmienne środowiskowe dla bieżącego skryptu, ustawiać i używać funkcji z bieżącego skryptu, ustawiać bieżący katalog, umask, ograniczenia i inne atrybuty dla bieżącego skryptu i tak dalej.bash -c "$1"
wykonuje polecenie w całkowicie osobnym skrypcie, który dziedziczy zmienne środowiskowe, deskryptory plików i inne środowisko procesowe (ale nie przesyła żadnych zmian z powrotem), ale nie dziedziczy wewnętrznych ustawień powłoki (zmienne powłoki, funkcje, opcje, pułapki itp.).Istnieje inny sposób,
(eval "$1")
który wykonuje polecenie w podpowłoce: dziedziczy wszystko ze skryptu wywołującego, ale nie przesyła żadnej zmiany z powrotem.Na przykład, zakładając, że zmienna
dir
nie jest eksportowana i$1
jestcd "$foo"; ls
, a następnie:cd /starting/directory; foo=/somewhere/else; eval "$1"; pwd
wyświetla zawartość/somewhere/else
i drukuje/somewhere/else
.cd /starting/directory; foo=/somewhere/else; (eval "$1"); pwd
wyświetla zawartość/somewhere/else
i drukuje/starting/directory
.cd /starting/directory; foo=/somewhere/else; bash -c "$1"; pwd
wyświetla zawartość/starting/directory
(ponieważcd ""
nie zmienia bieżącego katalogu) i drukuje/starting/directory
.źródło
(eval "$1")
nie ma z tym nic wspólnegosource
. To tylko połączenie(…)
ieval
.source foo
jest mniej więcej równoważne zeval "$(cat foo)"
.eval
i.dot
polega na tym, żeeval
działa z argumentami i.dot
z plikami.Najważniejsza różnica między
I
Czy to pierwsze działa w podpowłoce, a drugie nie. Więc:
WYDAJNOŚĆ:
WYDAJNOŚĆ:
Nie mam jednak pojęcia, dlaczego ktokolwiek miałby używać tego pliku wykonywalnego
bash
w ten sposób. Jeśli musisz go wywołać, użyj wbudowanej gwarancji POSIXsh
. Lub(subshell eval)
jeśli chcesz chronić swoje środowisko.Osobiście wolę
.dot
przede wszystkim muszle .WYNIK
ALE POTRZEBUJESZ W ogóle?
Jedynym powodem użycia jednego z nich jest to, że twoja zmienna faktycznie przypisuje lub ocenia inną, lub dzielenie słów jest ważne dla wyniku.
Na przykład:
WYDAJNOŚĆ:
To działa, ale tylko dlatego,
echo
że nie obchodzi go liczba argumentów.WYDAJNOŚĆ:
Widzieć? Pojawiają się podwójne cudzysłowy, ponieważ wynik rozszerzenia powłoki
$var
nie jest ocenianyquote-removal
.WYDAJNOŚĆ:
Ale z
eval
lubsh
:WYDAJNOŚĆ:
Kiedy używamy
eval
lubsh
powłoka bierze drugie przejście na wyniki rozszerzeń i ocenia je również jako potencjalne polecenie, więc cudzysłowy mają znaczenie. Możesz także:WYNIK
źródło
Zrobiłem szybki test:
(Tak, wiem, użyłem bash -c do wykonania pętli, ale to nie powinno mieć znaczenia).
Wyniki:
Tak
eval
jest szybciej. Ze strony podręcznika użytkownikaeval
:bash -c
oczywiście wykonuje polecenie w powłoce bash. Jedna uwaga: użyłem,/bin/echo
ponieważecho
jest to powłoka wbudowana wbash
, co oznacza, że nowy proces nie musi być uruchamiany. Wymiana/bin/echo
zecho
dobash -c
testu zajęło1.28s
. To mniej więcej to samo. Hovever,eval
jest szybszy do uruchamiania plików wykonywalnych. Kluczową różnicą jest to, żeeval
nie uruchamia nowej powłoki (wykonuje polecenie w bieżącej), podczas gdybash -c
uruchamia nową powłokę, a następnie wykonuje polecenie w nowej powłoce. Uruchomienie nowej powłoki wymaga czasu i dlategobash -c
jest wolniejsze niżeval
.źródło
bash -c
z tymeval
nie porównaćexec
.bash -c