Na przykład następujące polecenie nie działa:
if [[-e xyz]]; then echo File exists;fi
ksh daje następujący błąd
[[-e: command not found
Czy to dlatego, że „[[-” jest niejednoznaczny?
Na przykład następujące polecenie nie działa:
if [[-e xyz]]; then echo File exists;fi
ksh daje następujący błąd
[[-e: command not found
Czy to dlatego, że „[[-” jest niejednoznaczny?
Odpowiedzi:
Najprostszym wyjaśnieniem byłoby, ponieważ w instrukcji wydaje się, [[ expression ]]
więc nie musi być przestrzeń pomiędzy [[
a expression
i zamykanie ]]
. Ale oczywiście możemy spróbować przyjrzeć się temu bardziej szczegółowo. Muszle mają nieco złożoną gramatykę i polegają w dużej mierze na koncepcji „dzielenia słów”. W szczególności instrukcja ksh (1) stwierdza:
Powłoka zaczyna analizować dane wejściowe, dzieląc je na słowa. Słowa, które są sekwencjami znaków, są rozdzielane niecytowanymi białymi znakami (spacja, tabulator i nowa linia) lub metaznakami (<,>, |,;, &, (i)). Oprócz ograniczania słów spacje i tabulatory są ignorowane, podczas gdy znaki nowej linii zwykle ograniczają polecenia.
Tak jak podano w instrukcji, sekwencja znaków [[-e
jest uważana za słowo powłoki. ksh
szukałby takiego polecenia na liście wbudowanych i operatorów specjalnych (takich jak for
lub while
), a następnie szukał polecenia zewnętrznego - i voilà - nie znaleziono, stąd pojawia się komunikat o błędzie dotyczący polecenia nie znalezionego.
W tym przypadku [[
nie są też specjalnymi metaznakami. Gdyby tak było, ta -e
część [[-e
byłaby uważana za słowo powłoki, a nie argument [[
sam w sobie. Jest jednak [[
opisany jako polecenie złożone, a instrukcja mówi:
Polecenia złożone są tworzone przy użyciu następujących słów zastrzeżonych - słowa te są rozpoznawane tylko wtedy, gdy nie są cytowane i jeśli są używane jako pierwsze słowo polecenia (tzn. Nie mogą być poprzedzone przypisaniem parametrów ani przekierowaniem):
Aby więc [[
mógł zostać rozpoznany jako polecenie złożone, musi być pierwszym słowem polecenia lub listy poleceń, co zgodnie z poprzednią definicją „słowa” oznacza, że muszą być one oddzielone spacjami, tabulatorami lub znakami nowej linii od innych słowa / argumenty.
W komentarzach zapytałeś : „Dlaczego parser nie może zatrzymać się, gdy tylko znajdzie wzorzec” [[”, i traktuje to jako początek polecenia warunkowego?” Krótka odpowiedź jest prawdopodobnie spowodowana 1) wpływem [
składni, ponieważ pierwotnie była to komenda zewnętrzna, a dla POSIX standardowa zgodność istnieje już jako komenda zewnętrzna, a 2) ponieważ parser powłoki jest tak zbudowany. Analizator składni powłoki rozpoznaje inne znaki specjalne rozdzielane spacjami: echo $((2+2))
i (echo foobar)
działa doskonale. Być może w przyszłości, gdy ksh
programowanie zostanie wznowione lub pojawi się widelec lub klon (jak mksh
lub pdksh
), ktoś zaimplementuje składnię bez spacji [[-e
.
[[
nazywane jest „słowem zastrzeżonym” (patrz sekcja 2.9 języka poleceń powłoki ). Według definicji POSIX słowo zastrzeżone musi być oddzielone spacjami. Natomiast (
operator jest, a standardowe stany w sekcji 2.9 „reprezentacje obejmują odstępy między tokenami w niektórych miejscach, w których <blank>
s nie byłoby konieczne (gdy jeden z tokenów jest operatorem)”. Zobacz pokrewną dyskusję: Gramatyka powłoki POSIX: Dlaczego grupa Brace potrzebuje pierwszej przestrzeni, a podpowłoki nie?char
jest słowem kluczowym, ale nadal nie można pisać charsomeletter = 'A';
i oczekiwać, że parser zatrzyma się po zobaczeniu char
.
i--<=++j
, a kompilator nie ma problemu z analizowaniem tego jako i -- <= ++ j
.
_
). Ksh ma (
jako operator i (echo hello)
analizuje jako ( echo hello )
. To if
, {
, [[
, i inne słowa kluczowe , a ifx
, {x
i [[x
każdy jeden żeton - podobnie jak charsomeletter
to jeden żeton C. W przeciwieństwie do tego, cudzysłow (x
w ksh to dwa tokeny - podobnie jak i--
dwa tokeny w C. To, co koncepcyjnie oznacza nawet, że jest operatorem, różni się między powłokami typu Bourne'a (jak ksh) i C. Ale Peter A. Schneider zwrócił uwagę na prawdziwe podobieństwo leksykalne .
Należy zauważyć, że [
jest to polecenie, a słowo kluczowe powłoki [[
w bash i ksh jest oparte [
.
[[
jest używany w podobny sposób jak [
. Czasami można nawet zastąpić [
]
z [[
]]
bez zmiany zachowań. W przypadku [
, jak każdego polecenia, spacja jest obowiązkowa między poleceniem a jego argumentami. To samo dotyczy [[
.
Kiedyś mieliśmy tylko /usr/bin/[
. Teraz większość powłok ma [
wbudowaną wydajność - ale składnia jest taka sama. W powłokach, które to zapewniają [[
, działa ona jako bardziej wszechstronna alternatywa dla [
.
Oto opis [
w bash:
$ help [
[: [ arg... ]
Evaluate conditional expression.
This is a synonym for the "test" builtin, but the last argument must
be a literal `]', to match the opening `['.
[
Jest to więc równoważne z test
(poza oczekiwaniem ]
argumentu na samym końcu). help test
poda jeszcze więcej szczegółów. Możesz to porównać do help [[
.
Istnieje również strona podręcznika dla zewnętrznego polecenia [
( man \[
).
W przypadku
if [[-e
[
nie [[
ma polecenia. Pełne słowo [[-e
to.if [[-e
sprawia, że jest to test na wartość prawda / fałsz. Czy istnieje polecenie [[-e
? Czy to dlatego, że „[[-” jest niejednoznaczny?
Tak. Albo nie. [[-e
jest tym, czym jest: nic, co powłoka rozumie, więc zakłada, że jest to jej własne polecenie. ;-)
[[-e
to potencjalnie poprawna (choć dziwnie wyglądająca) nazwa polecenia.
Przestrzeń jest ogranicznikiem i jest wymagana. Jak widać z shellcheck
:
$ shellcheck gmail-browse-msgs-algorithm.sh
In gmail-browse-msgs-algorithm.sh line 847:
[[$Today != "${DaysArr[ i + DAY_DELETED_ON_NDX ]}" ]] && continue
^-- SC1035: You need a space after the [[ and before the ]].
(Zarówno obsługa ksh, jak i bash [[
i nie działa bez spacji. Shellcheck daje dokładnie takie wyjście z podobnymi skryptami ksh i bash zawierającymi tę błędną linię.)
Dlaczego separatory są potrzebne, mają związek z tokenami i leksykonami .
ksh
shell w pytaniu. Bash pożycza [[
operatora przed ksh
iw tej kwestii ich zachowanie jest identyczne, ale byłbym ostrożny z założeniami, jak istnieje kilka istotnych różnic ksh
i bash
zachowań i wewnętrznych. To dlatego, że shellcheck działa na skrypcie bash, niekoniecznie może być odpowiednim narzędziem dla skryptów ksh. Tylko coś, o czym należy pamiętać zbliżając się do różnych pocisków
[[
wbudowane reguły. W żaden sposób nie wywnioskowałem, że ksh
jest to powłoka, w której shellcheck
można znaleźć błędy. Mam nadzieję, że inni to docenią ksh
i bash
są dwoma różnymi tłumaczami. Dziękuję, że o tym wspomniałeś. Warto również zauważyć [[
wbudowane bash, podczas gdy [
jest to polecenie zewnętrzne.
[
jest też wbudowany w bash :) manpages.ubuntu.com/manpages/bionic/man7/bash-builtins.7.html Ale nie jesteś daleko - [
lub test
wymagane jest, aby być zewnętrznym poleceniem. W czasach, gdy oryginalna powłoka Bourne'a [
była w rzeczywistości zewnętrzną komendą i nadal istnieje, /usr/bin/[
ponieważ POSIX wymaga, aby była to zewnętrzna komenda pubs.opengroup.org/onlinepubs/009695399/utilities/test.html Bardzo niewiele jest wymaganych przez POSIX do bądź wbudowany pubs.opengroup.org/onlinepubs/009695399/idx/sbi.html Wbudowany [
jest dla wydajności
ksh
; użyj hashbanga lub -s ksh
. Btw, ksh i bash mają [[
„wbudowane”, ale jest to słowo kluczowe , w przeciwieństwie [
do wbudowanej powłoki . (ksh :; whence -v [ [[
bash type [ [[
:) Wbudowane i zewnętrzne polecenia są podobne pod względem składniowym. Jednym ze sposobów [[
różni się od [
tego, że [[
tłumi pewne rozszerzenia w swoich argumentach, których nie mógł jako wbudowane - podobnie jak {
grupowanie, gdyby nie było wbudowane. Być może dlatego {x
(lub [[x
) bycie jednym żetonem wydaje się dziwne. Myślę, że słusznie jest powiedzieć, że wbudowane i słowa kluczowe są leksykalnie, ale nie podobne pod względem składniowym . @SergiyKolodyazhnyy
[[
może być poleceniem zewnętrznym! Oznacza to, że może to być program, a nie jakaś składnia obsługiwana bezpośrednio przez powłokę. Obsługa składni bez przestrzeni byłaby możliwa, ksh
ale zawiodłaby w systemach z zewnętrznymi, [[
więc ze względu na kompatybilność lepiej zachować wymaganą przestrzeń.
BusyBox udostępnia [[
na przykład jako polecenie zewnętrzne .
Ponieważ [[-e
może uczestniczyć w rozszerzaniu powłoki (może być używany jak
echo [[-e]*
aby wymienić wszystkie pliki zaczynające się od litery pomiędzy [
i e
włącznie), byłby to kompletny bałagan, jeśli [
i ]
były znaki specjalne, które nie uczestniczą w normalnej spacji rządzone słowo podziału.
[[
jest słowem kluczowym - przypuszczalnie parsowanie drzewa powłoki wymaga, aby słowa kluczowe zostały określone przez spacje