Perché è richiesto uno spazio tra “[[” e “-e xxx” in ksh?


9

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?


2
[[è una parola chiave - presumibilmente l'albero di analisi della shell richiede che le parole chiave debbano essere delineate da spazi bianchi
steeldriver

Un altro modo di vederlo è probabilmente che potresti scrivere una funzione [[-, come la shell saprebbe analizzare "do the e flag su [[" invece di "do the function [[- on e".
pbhj,

Risposte:


15

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.

Guarda anche:


3
Penso che la citazione manuale di ksh sia davvero sul posto. È simile a qualsiasi altro linguaggio di programmazione: in C charè una parola chiave ma non puoi ancora scrivere charsomeletter = 'A';e aspettarti che il parser si fermi dopo aver visto char.
Peter - Ripristina Monica il

Penso che la differenza principale tra il tuo esempio di "carattere" e il simbolo "[[" nella domanda sia che un identificatore alfanumerico, in generale, ha bisogno del delimitatore di spazio per separarsi dagli altri; simboli speciali come token, d'altra parte, non hanno bisogno di delimitatori di spazio.
AcBap,

Esattamente. Non sono sicuro che il confronto con C sia utile. In C si può dire i--<=++j, e il compilatore non ha problemi a analizzarlo come i -- <= ++ j.
Scott,

@Scott Penso che il confronto C sia utile (e che sia un po 'secondario che gli identificatori C consentano solo caratteri alfanumerici e _). 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 .
Eliah Kagan

2

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è.
  • Lo 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. ;-)


"% help [[" afferma che "[[" è un comando condizionale. Perché il parser non può arrestarsi non appena trova il modello [["e lo considera come l'inizio di un comando condizionale?
AcBap

@Myloti [[-eè un nome comando potenzialmente valido (se strano).
Gordon Davisson,

2

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 .


Si noti che OP ha chiesto informazioni sulla 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
Sergiy Kolodyazhnyy,

@SergiyKolodyazhnyy Ero opportunista usando lo shellcheck per evidenziare le [[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.
WinEunuuchs2Unix

In realtà [è 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
Sergiy Kolodyazhnyy

2
Shellcheck lo sa 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
Eliah Kagan

1
@EliahKagan In realtà, ho pubblicato una domanda su U&L per ottenere una risposta precisa su cosa pensa POSIX di questa situazione unix.stackexchange.com/questions/526574/… Il linguaggio della shell è abbastanza complesso, quindi spero che qualcuno possa spiegarlo in termini più formali
Sergiy Kolodyazhnyy,

1

[[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.

BusyBox fornisce ad [[esempio un comando esterno .


0

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.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.