Ad esempio, il seguente comando non funziona:
if [[-e xyz]]; then echo File exists;fi
ksh dà il seguente errore
[[-e: command not found
È perché "[[-" è ambiguo?
Ad esempio, il seguente comando non funziona:
if [[-e xyz]]; then echo File exists;fi
ksh dà il seguente errore
[[-e: command not found
È perché "[[-" è ambiguo?
Risposte:
La spiegazione più semplice sarebbe, perché nel manuale appare come [[ expression ]]così ci deve essere spazio tra [[e expressione chiusura ]]. Ma ovviamente possiamo tentare di esaminarlo più in profondità. Le conchiglie hanno una grammatica alquanto complessa e si basano fortemente sul concetto di "scissione delle parole". In particolare, il manuale di ksh (1) afferma:
La shell inizia ad analizzare il suo input suddividendolo in parole. Le parole, che sono sequenze di caratteri, sono delimitate da caratteri di spazi bianchi non quotati (spazio, tabulazione e nuova riga) o meta-caratteri (<,>, |,;, &, (e)). A parte la delimitazione delle parole, gli spazi e le schede vengono ignorati, mentre le nuove righe di solito delimitano i comandi.
Quindi, come indicato nel manuale, la sequenza di caratteri [[-eè considerata una parola shell. kshcercherebbe tale comando nell'elenco di incorporati e operatori speciali (come foro while), quindi cercherebbe un comando esterno - e voilà - nessuno trovato, quindi c'è un messaggio di errore sul comando non trovato.
In questo caso [[non sono nemmeno meta-caratteri speciali. Se lo fossero, la -eparte in [[-esarebbe considerata una parola shell, non un argomento a [[sé. Tuttavia, [[viene descritto come comando composto e il manuale dice quanto segue:
I comandi composti vengono creati utilizzando le seguenti parole riservate: queste parole vengono riconosciute solo se non quotate e se vengono utilizzate come prima parola di un comando (ovvero, non possono essere precedute da assegnazioni di parametri o reindirizzamenti):
Quindi, per [[essere riconosciuto come comando composto, deve essere una prima parola di un comando o di un elenco di comandi, che per definizione precedente di una "parola" implica che deve essere separato da spazi, tabulazioni o newline da altri parole / argomenti.
Nei commenti hai chiesto : "Perché il parser non può fermarsi non appena trova" [["pattern, e lo considera come l'inizio di un comando condizionale?" La risposta breve è probabilmente perché 1) influenza della [sintassi poiché era originariamente un comando esterno, e per la conformità allo standard POSIX esiste ancora oggi come comando esterno, e 2) perché il parser della shell è costruito così. Shell parser è in grado di riconoscere altri caratteri speciali non delimitati da spazi: echo $((2+2))e (echo foobar)funziona perfettamente. Forse in futuro quando lo kshsviluppo riprende o sembra che ci sia un fork o un clone (come mksho pdksh) qualcuno implementerà la sintassi senza spazio [[-e.
[[viene chiamata "parola riservata" (vedere la sezione 2.9 del linguaggio di comando Shell ). Per definizione POSIX, la parola riservata deve essere delimitata da spazi. Al contrario (è un operatore, e gli stati standard nella sezione 2.9 "le rappresentazioni includono la spaziatura tra i token in alcuni punti in cui <blank>s non sarebbe necessario (quando uno dei token è un operatore)". Vedi la discussione correlata: POSIX Shell Grammar: Perché Brace Group ha bisogno del primo spazio, ma il Subshell no?charè una parola chiave ma non puoi ancora scrivere charsomeletter = 'A';e aspettarti che il parser si fermi dopo aver visto char.
i--<=++j, e il compilatore non ha problemi a analizzarlo come i -- <= ++ j.
_). Ksh ha (come operatore e (echo hello)analizza come ( echo hello ). E ' if, {, [[, e altre parole chiave , e ifx, {xe [[xsono ciascuna un gettone - come come charsomeletterè un gettone C. Al contrario, un non quotato (xin ksh è di due token - come i--è due token in C. Ciò che concettualmente significa anche essere un operatore differisce tra shell in stile Bourne (come ksh) e C. Ma Peter A. Schneider ha sottolineato un vera somiglianza lessicale .
Ciò che è importante notare è che [è un comando e [[su cui si basa la parola chiave shell in bash e ksh [.
[[è usato in modo simile a [. A volte si può anche sostituire [ ]con [[ ]]senza alcun cambiamento nel comportamento. Con [, come qualsiasi comando, uno spazio è obbligatorio tra il comando e i suoi argomenti. Lo stesso vale per [[.
Avevamo solo /usr/bin/[. Ora la maggior parte delle shell sono [integrate per l'efficienza, ma la sintassi è la stessa. Nelle shell che forniscono [[, funziona come un'alternativa più versatile a [.
Ecco la descrizione di [in 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 `['.
Quindi [equivale a test(a parte aspettarsi un ]argomento alla fine). help testfornirà ulteriori dettagli al riguardo. Puoi confrontare questo con help [[.
C'è anche una pagina man per il comando esterno [( man \[).
In caso di
if [[-e
[, né [[è un comando, lì. La parola completa [[-eè.if [[-erende un test per vero / falso. Quindi esiste un comando [[-e? È perché "[[-" è ambiguo?
Sì. O no. [[-eè quello che è: niente che la shell capisca, quindi presume che sia un suo comando. ;-)
[[-eè un nome comando potenzialmente valido (se strano).
Lo spazio è un deliminatore ed è necessario. Come puoi vedere da 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 ]].
(Sia ksh che bash supportano [[e non funzionano senza lo spazio. Shellcheck fornisce esattamente quell'output con script ksh e bash simili contenenti quella riga errata.)
Perché i criminali sono necessari ha a che fare con token e lessici .
kshshell nella domanda. Bash prende in prestito l' [[operatore da kshe in questa domanda il loro comportamento è identico, ma sarei prudente nei confronti delle ipotesi in quanto vi sono alcune differenze significative tra kshe bashcomportamento e interni. Questo è solo perché shellcheck funziona su bash script, potrebbe non essere necessariamente lo strumento appropriato per gli script ksh. Solo qualcosa da tenere a mente quando ci si avvicina a diverse conchiglie
[[regole integrate. In nessun modo deducevo che kshfosse una shell in cui si shellcheckpotevano trovare errori. Spero che gli altri apprezzino kshe bashsiano due interpreti diversi. Grazie per averlo menzionato. Da notare anche [[un bash incorporato mentre [è un comando esterno.
[è anche un built-in in bash :) manpages.ubuntu.com/manpages/bionic/man7/bash-builtins.7.html Ma non sei lontano - [o testdeve essere un comando esterno. Ai tempi della shell Bourne originale [era in realtà un comando esterno, ed esiste ancora oggi /usr/bin/[perché POSIX richiede che sia un comando esterno pubs.opengroup.org/onlinepubs/009695399/utilities/test.html Pochi sono necessari a POSIX per essere incorporato pubs.opengroup.org/onlinepubs/009695399/idx/sbi.html Builtin [è per l'efficienza
ksh; usa un hashbang o -s ksh. Btw, ksh e bash hanno [["built-in", ma è una parola chiave , a differenza di [, che è una shell incorporata . (ksh :; whence -v [ [[bash type [ [[:) I builtin e i comandi esterni sono sintatticamente simili. Un modo [[diverso da [quello è quello di [[sopprimere alcune espansioni nei suoi argomenti, che non potrebbe essere incorporato - tanto quanto {non potrebbe fare il raggruppamento se fosse incorporato. Questo può essere il motivo per cui {x(o [[x) essere un token sembra strano. Penso che sia giusto dire che i builtin e le parole chiave sono lessicali ma non sintatticamente simili. @SergiyKolodyazhnyy
[[può essere un comando esterno! Cioè, potrebbe essere un programma e non una sintassi supportata direttamente dalla shell. Supportare una sintassi senza spazio sarebbe possibile per kshma fallirebbe su sistemi con esterno, [[quindi per motivi di compatibilità è meglio mantenere lo spazio richiesto.
Poiché [[-epuò partecipare all'espansione della shell (può essere usato come
echo [[-e]*
al fine di elencare tutti i file che iniziano con una lettera tra [e einclusivamente), sarebbe un disastro completo se [e ]fossero caratteri speciali che non partecipano alla normale suddivisione delle parole governata da spazi bianchi.
[[è una parola chiave - presumibilmente l'albero di analisi della shell richiede che le parole chiave debbano essere delineate da spazi bianchi