[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Worth mentioning in documentation

From: Greg Wooledge
Subject: Re: Worth mentioning in documentation
Date: Fri, 7 Aug 2015 08:24:54 -0400
User-agent: Mutt/

On Fri, Aug 07, 2015 at 10:00:53AM +0200, Juanma wrote:
> El Thu 6 of Aug, Greg Wooledge profirió estas palabras:
> > I believe you are talking about the section that discusses the [[ ... ]]
> > command.
> Yes, you are right. And I mean, concretely, the last part:
> | Expressions may be combined using the following operators, listed in 
> decreasing order of precedence: 
> | ( expression )
> | Returns the value of expression. This may be used to override the normal 
> precedence of operators.
> | ...
> > Point 1: I truly have no idea what you mean.  What brackets are you
> > escaping, and how, and why?
> Those brackets I cited above: ( expression )

In the US we call those "parentheses", and we reserve the word "brackets"
(or "square brackets") for [ ].  I realize that the UK uses different
terminology.  Hence, the word is ambiguous and you should always type
the actual characters you mean.

> But I have to apologize because I have just realized that, while still being 
> a shell issue, it isn't a [[ issue: it's an issue with [.
>  [ 'a' == "b" -o 1 -lt 2 -a  1 -gt 0 ]  => return 1
>  [ ( 'a' == "b" -o 1 -lt 2 ) -a  1 -gt 0 ]
> bash: syntax error near unexpected token `'a''
>  [ \( 'a' == "b" -o 1 -lt 2 \) -a  1 -gt 0 ]  => return 0
> That's the escaping I meant.

Yes, the [ and [[ commands have totally different syntax.  This is
confusing and unfortunate.  You just have to live with it.

[[ is a "shell keyword" which means that it has special parsing rules
that don't apply to ordinary commands.  Among other things, you can
use shell metacharacters like ( and && inside [[ without escaping them.

[ is an ordinary command (a "shell builtin"), so it has no special
parsing rules.  Arguments to [ have to be escaped or quoted, exactly
the same way you would have to escape or quote them if you were
passing them to expr(1) or find(1).

> > Point 2: Spaces.
> [...]
> > The manual doesn't explicitly point out that you need spaces after "if"
> > or "case".  (It fails to mention that you can *omit* the spaces in the
> > ((...)) command, but that's a special exception.)
> The thing with brackets is that they are operators (if I'm not wrong), but 
> they need special treatment, compared to other operators: first, because they 
> need escaping; second, because they need spaces around them, as if they were 
> commands or operands:
>  [ \('a' == "b" -o 1 -lt 2\) -a  1 -gt 0 ]
> bash: [: 2): integer expression expected

P.S. == is not required to be supported by the [ command.  You should use =
instead.  Supporting == in [ is a bash extension.

> However, it seems like the quotes around a prevent the ambiguity in the case 
> of the opening bracket:  \('a'  That causes no error.
> Am I making any point now?

You were reading the section on [[ and assuming that it applies to [.
That's a huge mistake.

(It also didn't help that you talked about escaping "brackets" when
the command name in question is two brackets.  But you apparently meant
inner ( ) arguments within the command.)

Many bash users recommend ONLY using [[ and abandoning [ altogether.
(I actually disagree, and I often prefer using the portable syntax
when it can do what's needed.  But you'll have to decide for yourself.)

If you choose to use [ then you should use it in a portable way
(otherwise, there is no point).  And the first thing you need to know
about using [ portably is that you CANNOT use -a or -o ("and" or "or")
operators in it.  Don't even try!  Once you get that out of your head,
then you don't need parentheses ("UK brackets") either.

POSIX says that the behavior of [ depends on how many arguments you
pass to it.  It has very limited capability.

Here's the documentation:

Basically, almost any expression involving any combination of tests is
unspecified.  You just can't combine them in a single test or [ command.
What you should do instead is use multiple test or [ commands.

if test "$a" = foo && test -s "$outputfile" ; then

if [ ! -d "$dir1" ] || [ ! -d "$dir2" ] ; then

That is how you write compound conditional expressions using portable
POSIX sh syntax (with the [ or test commands).

If you choose to use [[ (a bash extension, also found in ksh) then
the rules are entirely different.  Within [[ you can join compound
expressions using && and ||.

if [[ ! -d $dir1 || ! -d $dir2 ]] ; then

Do not use -a or -o.  They might as well not EXIST.  Just forget them.
You can't use them in [ and you can't use them in test and you can't
use them in [[.

Use one of the syntaxes I've shown here.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]