For instance, the following command does not work:
if [[-e xyz]]; then echo File exists;fi
ksh gives the following error
[[-e: command not found
Is that because "[[-" is ambiguous?
For instance, the following command does not work:
if [[-e xyz]]; then echo File exists;fi
ksh gives the following error
[[-e: command not found
Is that because "[[-" is ambiguous?
The simplest explanation would be, because in the manual it appears as
[[ expression ]]
so there has to be space between[[
andexpression
and closing]]
. But of course we can attempt to look at it more in depth. Shells have somewhat complex grammar and rely heavily on the concept of "word splitting". In particular, ksh(1) manual states:So as stated in the manual, sequence of characters
[[-e
is considered a shell word.ksh
would look for such command in the list of built-ins and special operators ( likefor
orwhile
), then look for an external command - and voilà - none found, hence there's an error message about command not found.In this case
[[
are not special meta-characters either. If they were, the-e
part in[[-e
would be considered a shell word, not an argument to[[
itself. However,[[
is described as compound command, and the manual says the following:So in order for
[[
to be recognized as a compound command, it has to be a first word of a command or command list, which by previous definition of a "word" implies it has to be separated by spaces,tabs,or newlines from other words/arguments.You've asked in the comments: "Why can't the parser stop as soon as it finds "[[" pattern, and treats that as the start of a conditional command?" Short answer is probably because 1) influence of
[
syntax since it was originally an external command, and for POSIX standard compliance exists as external command even today, and 2) because the shell parser is built so. Shell parser can recognize other non-space delimited special characters:echo $((2+2))
and(echo foobar)
work perfectly fine. Maybe in future whenksh
development resumes or there appears to be a fork or clone (likemksh
orpdksh
) someone will implement space-less syntax in[[-e
.See also:
[[
is called a "reserved word" (see section 2.9 of Shell Command Language). By POSIX definition, reserved word has to be delimited by spaces. By contrast(
is an operator, and the standard states in section 2.9 "the representations include spacing between tokens in some places where<blank>
s would not be necessary (when one of the tokens is an operator)". See related discussion: POSIX Shell Grammar: Why Brace Group Needs First Space But Subshell Doesn't?What is important to note is that
[
is a command, and the shell keyword[[
in bash and ksh is based on[
.[[
is used in a similar way to[
. Sometimes you can even replace[
]
with[[
]]
with no change in behavior. With[
, like any command, a space is mandatory between the command and its arguments. The same applies to[[
.We used to have only
/usr/bin/[
. Now most shells have[
built in for efficiency—but the syntax is the same. In shells that provide[[
, it functions as a more versatile alternative to[
.Here is the description for
[
in bash:So
[
is equivalent totest
(aside from expecting a]
argument at the very end).help test
will give even more detail on it. You can compare this tohelp [[
.There is also a man page for the external command
[
(man \[
).In the case of
[
nor[[
is a command, there. The full word[[-e
is.if [[-e
makes it a test for true/false. So does a command[[-e
exist?Yes. Or no.
[[-e
is what it is: nothing that the shell understand so it assumes it is its own command. ;-)The space is a deliminator and is required. As you can see from
shellcheck
:(Both ksh and bash support
[[
and don't work without the space. Shellcheck gives exactly that output with similar ksh and bash scripts containing that buggy line.)Why deliminators are needed has to do with tokens and lexicons.
[[
can be an external command! That is, it may be a program and not some syntax supported by your shell directly. Supporting a space-less syntax would be possible forksh
but it would fail on systems with external[[
so for compatibility reasons it's better to keep the required space.BusyBox is providing
[[
as an external command, for example.Since
[[-e
can participate in shell expansion (it can be used likein order to list all files starting with a letter between
[
ande
inclusively), it would be a complete mess if[
and]
were special characters not participating in the normal whitespace-governed word splitting.