Podstawową ideą jest to, że VAR=VALUE some-command
ustawia VAR
się VALUE
na wykonanie some-command
kiedy some-command
jest zewnętrznym poleceniem i nie robi się to bardziej wymyślne. Jeśli połączysz tę intuicję z pewną wiedzą na temat działania powłoki, w większości przypadków powinieneś znaleźć właściwą odpowiedź. Odniesieniem do POSIX są „Proste polecenia” w rozdziale „Język poleceń powłoki” .
Jeśli some-command
jest poleceniem zewnętrznym , VAR=VALUE some-command
jest równoważne z env VAR=VALUE some-command
. VAR
jest eksportowany w środowisku some-command
, a jego wartość (lub brak wartości) w powłoce się nie zmienia.
Jeśli some-command
jest funkcją , to VAR=VALUE some-command
jest równoważne VAR=VALUE; some-command
, tj . Przypisanie pozostaje na miejscu po powrocie funkcji, a zmienna nie jest eksportowana do środowiska. Powodem tego jest konstrukcja powłoki Bourne'a (a następnie zgodność wsteczna): nie miała możliwości zapisywania i przywracania wartości zmiennych wokół wykonywania funkcji. Brak eksportowania zmiennej ma sens, ponieważ funkcja jest wykonywana w samej powłoce. Jednak ksh (w tym zarówno ATT ksh93, jak i pdksh / mksh), bash i zsh implementują bardziej użyteczne zachowanie, które VAR
jest ustawiane tylko podczas wykonywania funkcji (jest również eksportowane). W ksh odbywa się to, jeśli funkcja jest zdefiniowana za pomocą składni kshfunction NAME …
, nie jeśli jest zdefiniowany ze standardową składnią NAME ()
. W bash odbywa się to tylko w trybie bash, a nie w trybie POSIX (po uruchomieniu z POSIXLY_CORRECT=1
). W zsh odbywa się to, jeśli posix_builtins
opcja nie jest ustawiona; ta opcja nie jest ustawiona domyślnie, ale jest włączona przez emulate sh
lub emulate ksh
.
Jeśli some-command
jest wbudowane, zachowanie zależy od typu wbudowanego. Specjalne wbudowane zachowują się jak funkcje. Specjalne wbudowane to te, które muszą zostać zaimplementowane w powłoce, ponieważ wpływają na powłokę stanu (np. Wpływają na break
przepływ sterowania, cd
wpływają na bieżący katalog, set
wpływają na parametry pozycyjne i opcje…). Inne wbudowane funkcje są wbudowane tylko dla wydajności i wygody (głównie - np. Funkcja bash printf -v
może być zaimplementowana tylko przez wbudowane) i zachowują się jak polecenie zewnętrzne.
Przypisanie odbywa się po rozwinięciu aliasu, więc jeśli some-command
jest to alias , rozwiń go najpierw, aby znaleźć, co się stanie.
Zauważ, że we wszystkich przypadkach przypisanie jest wykonywane po przeanalizowaniu wiersza poleceń, w tym wszelkich podstawień zmiennych w samym wierszu poleceń. Tak var=a; var=b echo $var
drukuje a
, ponieważ $var
jest oceniane przed przypisaniem. I w ten sposób IFS=. printf "%s\n" $var
używa starej IFS
wartości do podziału $var
.
Omówiłem wszystkie typy poleceń, ale jest jeszcze jeden przypadek: gdy nie ma polecenia do wykonania , tj. Jeśli polecenie składa się tylko z przypisań (i ewentualnie przekierowań). W takim przypadku przypisanie pozostaje na miejscu . VAR=VALUE OTHERVAR=OTHERVALUE
jest równoważne z VAR=VALUE; OTHERVAR=OTHERVALUE
. Więc po IFS=. arr=($var)
, IFS
pozostaje ustawiony na .
. Ponieważ można użyć $IFS
w przypisaniu arr
z oczekiwaniem, że ma już swoją nową wartość, sensowne jest, aby nowa wartość parametru IFS
była używana do rozszerzenia $var
.
Podsumowując, możesz użyć tylko IFS
do tymczasowego podziału pola:
- uruchamiając nową powłokę lub podpowłokę (np.
third=$(IFS=.; set -f; set -- $var; echo "$3")
jest to skomplikowany sposób, z third=${var#*.*.}
wyjątkiem tego, że zachowują się inaczej, gdy wartość parametru var
zawiera mniej niż dwa .
znaki);
- w ksh,
IFS=. some-function
gdzie gdzie some-function
jest zdefiniowane za pomocą składni ksh function some-function …
;
- w bash i zsh, o
IFS=. some-function
ile działają one w trybie macierzystym, a nie w trybie zgodności.
IFS
pozostaje ustawiony na.
” Eek. Po przeczytaniu pierwszej części ma to sens, ale zanim opublikowałem to pytanie, nie spodziewałbym się tego.Odpowiedź @Gilles jest naprawdę świetna, wyjaśnia (szczegółowo) złożony problem.
Uważam jednak, że odpowiedź na pytanie, dlaczego to polecenie:
działa tak, jak działa. Prostym pomysłem jest przeanalizowanie całego wiersza poleceń przed jego wykonaniem. I że każde „słowo” jest przetwarzane raz przez powłokę.
Te zadania, takie jak
IFS=.
, są opóźnione (krok 4 jest ostatni):do momentu tuż przed wykonaniem polecenia i przetworzeniem wszystkich rozszerzeń argumentów w celu zbudowania tej linii wykonywalnej:
Wartość parametru
$var
jest rozszerzana o „stary” IFS do,a.b.c
zanim komendaprintf
otrzyma argumenty"%s\n"
ia.b.c
.Eval
Jeden poziom opóźnienia można wprowadzić poprzez
eval
:Linia jest analizowana (pierwszy raz) i „IFS =.” jest ustawiony na środowisko, ponieważ:
Następnie jest ponownie analizowany:
I wykonano na to:
Wartość
$var
(ABC) jest dzielona z wartością IFS w użyciu:.
.Środowisko
Złożona i skomplikowana część jest ważna w środowisku, kiedy !!!
Wyjaśnia to bardzo dobrze pierwsza część odpowiedzi Gillesa.
Z dodatkowym szczegółem.
Po wykonaniu tego polecenia:
Wartość IFS jest zachowana w obecnym środowisku, tak:
IFS dla pojedynczej instrukcji.
Można jednak tego uniknąć: ustawienie IFS dla pojedynczej instrukcji
źródło
Twoje pytanie dotyczące
jest skrzynką narożną.
Wynika to z faktu, że
macro expansion
polecenie in występuje przed ustawieniem zmiennej powłokiIFS=.
.Innymi słowy: po
$var
rozwinięciu poprzedniaIFS
wartość jest aktywna, a następnieIFS
jest ustawiona na'.'
.źródło