Por exemplo, o seguinte comando não funciona:
if [[-e xyz]]; then echo File exists;fi
ksh fornece o seguinte erro
[[-e: command not found
Isso é porque "[[-" é ambíguo?
command-line
syntax
ksh
AcBap
fonte
fonte
[[
é uma palavra-chave - presumivelmente árvore de análise do shell requer que palavras-chave devem ser delimitadas por espaços em brancoRespostas:
A explicação mais simples seria, porque no manual parece que
[[ expression ]]
deve haver espaço entre[[
eexpression
e fechando]]
. Mas é claro que podemos tentar analisá-lo mais profundamente. Os reservatórios têm uma gramática um tanto complexa e dependem muito do conceito de "divisão de palavras". Em particular, o manual do ksh (1) declara:Portanto, como declarado no manual, a sequência de caracteres
[[-e
é considerada uma palavra concha.ksh
procuraria por esse comando na lista de operadores internos e especiais (comofor
ouwhile
), depois procuraria por um comando externo - e pronto - nenhum encontrado, portanto, há uma mensagem de erro sobre o comando não encontrado.Nesse caso,
[[
também não são meta-caracteres especiais. Se fossem, a-e
parte[[-e
seria considerada uma palavra concha, não um argumento para[[
si mesma. No entanto,[[
é descrito como comando composto e o manual diz o seguinte:Portanto, para
[[
ser reconhecido como um comando composto, ele deve ser a primeira palavra de um comando ou lista de comandos, que por definição anterior de uma "palavra" implica que ela deve ser separada por espaços, tabulações ou novas linhas de outras palavras / argumentos.Você perguntou nos comentários : "Por que o analisador não pode parar assim que encontra o padrão" [["e trata isso como o início de um comando condicional?" A resposta curta é provavelmente porque 1) influência da
[
sintaxe, uma vez que era originalmente um comando externo, e para a conformidade com o POSIX existe como comando externo ainda hoje, e 2) porque o analisador de shell é construído assim. O analisador de shell pode reconhecer outros caracteres especiais não delimitados por espaço:echo $((2+2))
e(echo foobar)
funciona perfeitamente bem. Talvez no futuro, quando oksh
desenvolvimento for retomado ou pareça haver um fork ou clone (comomksh
oupdksh
), alguém implementará uma sintaxe sem espaço[[-e
.Veja também:
[[
é chamada de "palavra reservada" (consulte a seção 2.9 da Shell Command Language ). Pela definição do POSIX, a palavra reservada deve ser delimitada por espaços. Por outro lado,(
é um operador, e os estados padrão na seção 2.9 "as representações incluem espaçamento entre tokens em alguns lugares onde<blank>
s não seria necessário (quando um dos tokens é um operador)". Veja a discussão relacionada: POSIX Shell Grammar: Por que o Brace Group precisa do primeiro espaço, mas o subshell não?fonte
char
é uma palavra-chave, mas você ainda não pode escrevercharsomeletter = 'A';
e espera que o analisador pare depois de verchar
.i--<=++j
, e o compilador não tem problema em analisar isso comoi -- <= ++ j
._
). O Ksh tem(
como operador e(echo hello)
analisa como( echo hello )
. Temif
,{
,[[
, e outras palavras-chave , eifx
,{x
e[[x
são cada um símbolo - como a forma comocharsomeletter
é um símbolo C. Por outro lado, um não citado(x
em ksh é dois tokens - comoi--
é o caso de dois tokens em C. O que significa conceitualmente ser um operador difere entre as conchas no estilo Bourne (como ksh) e C. Mas Peter A. Schneider apontou uma semelhança lexical real .O que é importante notar é que
[
é um comando, e a palavra-chave shell[[
no bash e ksh é baseada[
.[[
é usado de maneira semelhante a[
. Às vezes você pode até mesmo substituir[
]
com[[
]]
com nenhuma mudança no comportamento. Com[
, como qualquer comando, um espaço é obrigatório entre o comando e seus argumentos. O mesmo se aplica a[[
.Nós costumávamos ter apenas
/usr/bin/[
. Agora a maioria dos shells foi[
incorporada para obter eficiência - mas a sintaxe é a mesma. Nas conchas que fornecem[[
, ele funciona como uma alternativa mais versátil[
.Aqui está a descrição para
[
no bash:Então
[
é equivalente atest
(além de esperar um]
argumento no final).help test
dará ainda mais detalhes sobre isso. Você pode comparar isso comhelp [[
.Há também uma página de manual para o comando externo
[
(man \[
).No caso de
[
nem[[
é um comando, não. A palavra completa[[-e
é.if [[-e
torna um teste para verdadeiro / falso. Então ,[[-e
existe um comando ?Sim. Ou não.
[[-e
é o que é: nada que o shell entenda para assumir que é seu próprio comando. ;-)fonte
[[-e
é um nome de comando potencialmente válido (se de aparência estranha).O espaço é um deliminador e é necessário. Como você pode ver em
shellcheck
:(O ksh e o bash suportam
[[
e não funcionam sem o espaço. O Shellcheck fornece exatamente essa saída com scripts semelhantes do ksh e do bash que contêm essa linha de buggy.)Por que os deliminadores são necessários tem a ver com tokens e léxicos .
fonte
ksh
shell na pergunta. Bash empresta[[
operadorksh
e nesta questão o seu comportamento é idêntico, mas eu seria cauteloso de pressupostos como há algumas diferenças significativas entreksh
ebash
comportamento e internos. Isso ocorre porque o shellcheck funciona no script bash, pode não ser necessariamente a ferramenta apropriada para os scripts ksh. Só uma coisa a ter em mente quando se aproxima de escudos diferentes[[
regras internas. Eu não estava de maneira alguma inferindo queksh
era um shell queshellcheck
poderia encontrar erros. Espero que outros apreciemksh
ebash
sejam dois intérpretes diferentes. Obrigado por mencionar isso. Também digno de nota[[
é um bash embutido enquanto[
é um comando externo.[
também é um bash embutido :) manpages.ubuntu.com/manpages/bionic/man7/bash-builtins.7.html Mas você não está muito longe -[
outest
é necessário que seja um comando externo. Na época original, o shell Bourne[
era de fato um comando externo, e ainda existe hoje em dia,/usr/bin/[
porque o POSIX exige que seja um comando externo pubs.opengroup.org/onlinepubs/009695399/utilities/test.html Poucos são exigidos pelo POSIX para ser embutido pubs.opengroup.org/onlinepubs/009695399/idx/sbi.html Builtin[
é para eficiênciaksh
; use um hashbang ou-s ksh
. Btw, ksh e bash foram[[
"incorporados", mas é uma palavra - chave , ao contrário[
, que é um shell embutido . (ksh :;whence -v [ [[
bashtype [ [[
:) Builtins e comandos externos são sintaticamente iguais. Uma maneira de[[
diferir[
disso é que[[
suprime algumas expansões em seus argumentos, o que não poderia ser incorporado - tanto quanto{
não poderia fazer agrupamentos se fosse interno. Pode ser por isso que{x
(ou[[x
) ser um token parece estranho. Eu acho que é certo dizer que builtins e palavras-chave são lexicamente, mas não sintaticamente semelhantes. @SergiyKolodyazhnyy[[
pode ser um comando externo! Ou seja, pode ser um programa e não uma sintaxe suportada diretamente pelo seu shell. Seria possível oferecer suporte a uma sintaxe sem espaço,ksh
mas ela falharia em sistemas externos,[[
portanto, por motivos de compatibilidade, é melhor manter o espaço necessário.O BusyBox está fornecendo
[[
como um comando externo , por exemplo.fonte
Uma vez que
[[-e
pode participar da expansão do shell (pode ser usado comopara listar todos os arquivos que começam com uma letra entre
[
ee
inclusive), seria uma bagunça completa se[
e]
se caracteres especiais não participassem da divisão normal de palavras governada por espaço em branco.fonte