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

Re: Bash script problem



On Thu, Aug 05, 2021 at 10:38:47AM +0200, tomas@tuxteam.de wrote:
> On Thu, Aug 05, 2021 at 09:26:35AM +0100, Tixy wrote:
> > ; has no special meaning inside "". The expression is true because
> > there is only a single non-null argument between the [ ]

Precisely.  But you're probably not explaining it in a way the OP will
understand.  Let's come back to that in a moment.

>   echo A="0 ;  "
>   => A=0 ;

I'm not sure that helps much.

>   echo -n '<' ; echo -n A="0 ;  " ; echo '>'
>   => <A=0 ;  >

Why not simply echo "A=<$A>" ?  (Or printf, to be safer, but we'll save
that for a different email.  The OP doesn't seem able to absorb too many
concepts at once.)

Now, as promised, How The Test Command Works.

The test command evolved over time.  There are several different original
versions with slightly different behaviors, and even modern shells offer
some extensions to the basic standard.

In order to make everything consistent, POSIX decreed that test shall work
as follows:

The first thing it does is *COUNT* the number of arguments that it
receives.  It is impossible to overstate the importance of this.  No
matter how much you think your test command looks like it should do XYZ,
it's the number of arguments that determines what it actually does.

As Tixy said, when you have

[ A="foo" ]

you are passing *one* argument to test.  (Two arguments to the [ form,
but the final ] argument gets removed, so in the end, it's one argument
that actually counts.)

When test is given one argument, what it does is check the *length*
of that argument.  If the length is 0, the expression is treated as
"false", and test exits with status 1 (false/failure).  Otherwise, if
the length is not 0, it's treated as "true", and test exits with status 0
(true/success).

It doesn't matter *what* the string is.  All of the following generate
a "true" result:

test foobar
test true
test false
test 0
test 1
test A=B
test 2+2=5
test 'your mother was a hamster'
test "$a=$b"

It doesn't matter what the argument is, as long as it's not the empty
string.  In that last example, it doesn't even matter what $a and $b
expand to.  We're guaranteed there's at least an = sign in between them,
so we know it will never be an empty string.

When test is given *two* arguments, there are two valid forms that it
will look for:

test ! somestring
test -? something

That is, the first argument must be either a literal exclamation point,
or it must be a unary test operator which is spelled with a hyphen and
then some letter (-e or -d or -x, etc.).

If the first argument isn't either of those, the result is "unspecified".
It will probably be an error, unless your shell overrides it for some
reason.

unicorn:~$ test one two
bash: test: one: unary operator expected

If the first argument is ! then it simply does the reverse of the
one-argument check.  It looks at the length of the second argument.
If the second argument is the empty string, test exits with status 0
(success/true).  If the second argument is *not* the empty string, it
exits with status 1 (failure/false).

If the first argument is one of the unary operators, such as -d, then
the corresponding test is performed on the second argument.  In the case
of -d, it means "check whether the second argument is a directory".  And
so on.

There are also 3-argument and 4-argument forme, but I'm not going to
cover them here, because this is already long enough, and I'm basically
just repeating the POSIX man page with extra details and examples.

If you want to read the official documentation, it's at

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html

or if you prefer, you can install the manpages-posix package, and
then run "man 1posix test".


So, what does all of this actually mean?

It means you *cannot* omit the whitespace when you write your test
(or [) commands.

These are correct:

test "$a" = b
[ "$a" = b ]

These are *not* correct:

test "$a"=b
[ "$a"=b ]
["$a" = b]
["$a"=b]

And so on.

See also <https://mywiki.wooledge.org/BashPitfalls#pf10>, and the pitfall
after that, or for bonus credit, the entire BashPitfalls page.


Reply to: