Istnieje duża różnica między wbudowanym a słowem kluczowym w sposobie, w jaki Bash analizuje kod. Zanim porozmawiamy o różnicy, wypiszmy wszystkie słowa kluczowe i wbudowane:
Wbudowane:
$ compgen -b
. : [ alias bg bind break
builtin caller cd command compgen complete compopt
continue declare dirs disown echo enable eval
exec exit export false fc fg getopts
hash help history jobs kill let local
logout mapfile popd printf pushd pwd read
readarray readonly return set shift shopt source
suspend test times trap true type typeset
ulimit umask unalias unset wait
Słowa kluczowe:
$ compgen -k
if then else elif fi case
esac for select while until do
done in function time { }
! [[ ]] coproc
Zauważ, że na przykład [
jest wbudowany i to [[
jest słowo kluczowe. Użyję tych dwóch, aby zilustrować różnicę poniżej, ponieważ są one dobrze znanymi operatorami: wszyscy je znają i używają ich regularnie (lub powinni).
Słowo kluczowe jest skanowane i rozumiane przez Bash na bardzo wczesnym etapie jego analizy. Umożliwia to na przykład:
string_with_spaces='some spaces here'
if [[ -n $string_with_spaces ]]; then
echo "The string is non-empty"
fi
To działa dobrze, a Bash z przyjemnością wyświetli
The string is non-empty
Pamiętaj, że nie cytowałem $string_with_spaces
. Mając na uwadze, że:
string_with_spaces='some spaces here'
if [ -n $string_with_spaces ]; then
echo "The string is non-empty"
fi
pokazuje, że Bash nie jest szczęśliwy:
bash: [: too many arguments
Dlaczego działa ze słowami kluczowymi, a nie z wbudowanymi? ponieważ kiedy Bash analizuje kod, widzi, [[
które jest słowem kluczowym i bardzo wcześnie rozumie, że jest wyjątkowy. Będzie więc szukał zamknięcia ]]
i potraktuje wnętrze w specjalny sposób. Wbudowane (lub polecenie) jest traktowane jako rzeczywiste polecenie, które będzie wywoływane z argumentami. W tym ostatnim przykładzie bash rozumie, że powinien uruchomić polecenie [
z argumentami (pokazane po jednym w wierszu):
-n
some
spaces
here
]
ponieważ następuje rozwijanie zmiennych, usuwanie cytatów, rozwijanie nazw ścieżek i dzielenie słów. Komenda [
okazuje się być wbudowana w powłokę, więc wykonuje ją z tymi argumentami, co powoduje błąd, stąd skarga.
W praktyce widać, że to rozróżnienie pozwala na wyrafinowane zachowanie, które nie byłoby możliwe w przypadku wbudowanych poleceń (lub poleceń).
W praktyce, jak możesz odróżnić wbudowane narzędzie od słowa kluczowego? to zabawny eksperyment do wykonania:
$ a='['
$ $a -d . ]
$ echo $?
0
Kiedy Bash analizuje linię $a -d . ]
, nie widzi nic specjalnego (tj. Żadnych aliasów, żadnych przekierowań, żadnych słów kluczowych), więc po prostu wykonuje zmienną interpretację. Po zmiennych rozszerzeniach widzi:
[ -d . ]
tak wykonuje polecenia (wbudowane) [
z argumentami -d
, .
i ]
, co oczywiście jest prawdą (to tylko testy czy .
jest katalogiem).
Nowy wygląd:
$ a='[['
$ $a -d . ]]
bash: [[: command not found
O. Dzieje się tak, ponieważ gdy Bash widzi tę linię, nie widzi nic specjalnego, a zatem rozwija wszystkie zmienne i ostatecznie widzi:
[[ -d . ]]
W tej chwili rozszerzenia aliasów i skanowanie słów kluczowych były już od dawna wykonywane i nie będą już wykonywane, więc Bash próbuje znaleźć polecenie o nazwie [[
, nie znajduje go i narzeka.
Wzdłuż tych samych linii:
$ '[' -d . ]
$ echo $?
0
$ '[[' -d . ]]
bash: [[: command not found
i
$ \[ -d . ]
$ echo $?
0
$ \[[ -d . ]]
bash: [[: command not found
Rozszerzenie aliasu jest również czymś wyjątkowym. Wszyscy przynajmniej raz wykonaliście następujące czynności:
$ alias ll='ls -l'
$ ll
.... <list of files in long format> ....
$ \ll
bash: ll: command not found
$ 'll'
bash: ll: command not found
Rozumowanie jest takie samo: rozwinięcie aliasu następuje na długo przed rozwinięciem zmiennej i usunięciem cytatu.
Słowo kluczowe a Alias
Jak myślisz, co się stanie, jeśli zdefiniujemy alias jako słowo kluczowe?
$ alias mytest='[['
$ mytest -d . ]]
$ echo $?
0
Och, to działa! więc aliasy mogą być używane do aliasu słów kluczowych! dobrze wiedzieć.
Wniosek: wbudowane naprawdę zachowują się jak polecenia: odpowiadają one wykonywanej akcji z argumentami, które podlegają bezpośredniemu rozszerzaniu zmiennych oraz dzieleniu i dzieleniu słów. To naprawdę tak, jakby mieć gdzieś zewnętrzną komendę /bin
lub /usr/bin
jest ona wywoływana z argumentami podanymi po rozwinięciu zmiennej itp. Zauważ, że kiedy mówię, to tak naprawdę, jak z zewnętrzną komendą, mam na myśli tylko w odniesieniu do argumentów, dzielenia słów, globowania, zmienna ekspansja itp. Wbudowany może modyfikować wewnętrzny stan powłoki!
Z drugiej strony słowa kluczowe są skanowane i rozumiane bardzo wcześnie i umożliwiają wyrafinowane zachowanie powłoki: powłoka będzie mogła zabronić dzielenia słów lub rozwijania nazw ścieżek itp.
Teraz spójrz na listę wbudowanych i słów kluczowych i spróbuj dowiedzieć się, dlaczego niektóre muszą być słowami kluczowymi.
!
jest słowem kluczowym. Wydaje się, że można by naśladować jego zachowanie za pomocą funkcji:
not() {
if "$@"; then
return false
else
return true
fi
}
ale to zabraniałoby konstrukcji takich jak:
$ ! ! true
$ echo $?
0
lub
$ ! { true; }
echo $?
1
To samo dla time
: bardziej wydajne jest użycie słowa kluczowego, aby mógł on mierzyć złożone polecenia złożone i potoki z przekierowaniami:
$ time grep '^#' ~/.bashrc | { i=0; while read -r; do printf '%4d %s\n' "$((++i))" "$REPLY"; done; } > bashrc_numbered 2>/dev/null
Gdyby time
zwykłe polecenie (nawet wbudowane), widziałoby tylko argumenty grep
, ^#
a /home/gniourf/.bashrc
tym razem, a następnie jego dane wyjściowe przechodziłyby przez pozostałe części potoku. Ale dzięki słowu kluczowemu Bash poradzi sobie ze wszystkim! może time
kompletny potok, w tym przekierowania! Gdyby to time
było zwykłe polecenie, nie moglibyśmy zrobić:
$ time { printf 'hello '; echo world; }
Spróbuj:
$ \time { printf 'hello '; echo world; }
bash: syntax error near unexpected token `}'
Spróbuj naprawić (?) To:
$ \time { printf 'hello '; echo world;
time: cannot run {: No such file or directory
Beznadziejny.
Słowo kluczowe a alias?
$ alias mytime=time
$ alias myls=ls
$ mytime myls
Jak myślisz, co się dzieje?
Naprawdę, wbudowane jest jak polecenie, tyle że jest wbudowane w powłokę, podczas gdy słowo kluczowe pozwala na wyrafinowane zachowanie! możemy powiedzieć, że jest to część gramatyki powłoki.