Twoje pierwsze przypuszczenie było słuszne, ale użyłeś złego przykładu. Gdy powłoka odczytuje polecenie
foo=bar echo $foo
pierwszą rzeczą, jaką robi (lub przynajmniej jedną z pierwszych rzeczy) jest poszukiwanie referencji zmiennych (jak $foo
) i ich ocena.
Następnie przetwarza to, co zostało z linii. (Może to być trochę nadmierne uproszczenie; szczegółowe informacje można znaleźć bash(1)
w Instrukcji obsługi Bash ). Masz więc polecenie
echo (nic)
biegać z foo=bar
; ale jest za późno; nie ma już nic, na co można spojrzeć $foo
. Możesz to zademonstrować za pomocą następującej sekwencji:
$ foo=oldvalue
$ foo=bar echo "$foo"
oldvalue
Ale
polecenie foo = bar
jest droga. Oto kilka przykładów, które działają:
foo=bar sh -c 'echo "$foo"'
i
foo=bar env
(Możesz to przepuścić grep foo
).
Właśnie zauważyłem cytowane zdanie: „Gdy te instrukcje przypisania poprzedzają polecenie wbudowane w powłokę, na przykład…”, sugerując, że wbudowane polecenia (takie jak echo
) reprezentują szczególny przypadek. Jest dla mnie intuicyjne (przynajmniej dla mnie), że ten „zakres poleceń”, którego szukasz, musiałby działać, ustawiając zmienną środowiskową w procesie potomnym, i nie jest jasne, jak by to działało dla wbudowanego polecenia, który nie działa w procesie potomnym. Niewiele wbudowanych poleceń ma bezpośredni dostęp do środowiska, a ich interakcja ze zmiennymi powłoki jest czasami tajemna. Ale wymyśliłem kilka innych przykładów, które mogą być bardziej tym, czego szukasz:
foo=bar eval 'echo $foo'
wyświetli „pasek”, ponieważ ocena $foo
jest odroczona. Jest on obsługiwany przez eval
(wbudowane) polecenie, a nie przez początkowe polecenie parsowania powłoki. Lub utwórz plik tekstowy o nazwie (na przykład) showme.sh
. Umieść w nim echo $foo
(lub echo "$foo"
) polecenie i powiedz
foo=bar . showme.sh
Prawdopodobnie o tym mówi Twoja książka, gdy mówi: „… powłoka musi śledzić prawidłową kolejność rozwiązywania odwołań do zmiennych…”. W jakiś sposób powłoka uruchamia polecenia showme.sh
z foo
równą bar
, a następnie powraca do poprzednia wartość foo
(jeśli istnieje), gdy wraca do pierwotnego wejścia (terminala).
$foo
„rozszerza się”, zanim cokolwiek innego się wydarzy. Zaktualizowałem odpowiedź, dodając więcej przemyśleń na temat wbudowanych poleceń.echo '$foo'
wyprowadza ciąg$foo
.cat '$foo'
ils -l '$foo’
poszukaj pliku o nazwie$foo
.grep '$foo' .bashrc
szuka ciągu$foo
w twoim.bashrc
pliku. Ale powłoka, w przeciwieństwie do innych programów, traktuje$
specjalnie;sh -c '$foo'
szuka zmiennej środowiskowej o nazwiefoo
. Na przykładfoo=date sh -c '$foo'
uruchomidate
polecenie. (Porównaj z faktem, żecat '\0107'
ils -l '\0107’
poszukaj pliku o nazwie\0107
igrep '\0107'
wyszukuje ciąg\0107
, aleecho -e '\0107'
wyprowadza ciągG
,… ( ciąg dalszy)echo
traktuje\
specjalnie, jeśli-e
opcja jest podana.)Problem polega na tym, że rozwinięcie zmiennej (
$foo
→ wartość) następuje przed oceną całego polecenia (włóżfoo=bar
do środowiska, uruchomecho ...
).Będzie działać dla poleceń, które same uzyskują dostęp do środowiska:
Bash tak naprawdę nie ma odpowiedniego zakresu dla tego, czego szukasz; musisz użyć sztuczki „podprocesu”, aby uzyskać nowy proces dla polecenia. (Oczywiście oznacza to, że zakres jest tylko do odczytu, żadne zmiany nie dotrą do elementu nadrzędnego ...) Użyj,
( ... )
aby utworzyć podpowłokę:źródło