Bash has "help test" for a quick cheatsheet.
The [ command is very old; it was already present in Version 7 Unix in 1979.
Yes, `[` is a command, and has a man page and everything, but in a script it doesn't look like a command. It looks like something "special" is going on.
Whereas using `test` emphasises the point that you're just running another program. That all `if` does is check the output status of whatever program is being run, whether that's `test`/`[`, or `grep`, or anything else at all.
(Personally, I don't think that emphasis is necessary. But I've been using shell scripts long enough that I understand these nuances fairly well without having to think about them much any more. So I think that GP's point is a reasonable perspective to have, and worth considering.)
while [ 1 ]; do ...; done
which are a pretty clear indication of the author's misconception about the perceived nature of [ ], I think. while true; do ...; done
There is never any reason to use test, other than portability to some broken environment that is missing [ but not missing test.What's the reason for always using [ ?
(Making life easier for others and your self)
test -d /nix && echo "$_ exists" || echo "$_ doesn’t exist"
You cannot do this with [ – Don’t Repeat Yourself, and your scripts become more maintainable.(Not POSIX-compliant. Documented in Bash and Zsh.)
$_ is nto documented in the man page but is in the Info manual. It is not only set to the last argument of a command but also to the script name on script startup.
$ bash --version
GNU bash, version 4.4.20(1)-release (i686-pc-linux-gnu)
[ ... ]
Contents of script: $ cat underscore.sh
#!/bin/sh
# ^^ mistake here, should be /bin/bash
test -e foo && echo $_ exists
echo 'value of $_' = $_
Test: $ touch foo
$ ./underscore.sh
./underscore.sh exists
value of $_ = ./underscore.sh
I'm seeing nothing but the behavior of $_ being set to the script, and not affected.But at the interactive prompt:
$ test -e foo && echo $_ exists
foo exists
This doesn't look like something I can rely on in scripts.In the first place, I code in POSIX, except in the rare situation of making something that is strictly geared toward Bash.
Magic global variables subject to hidden side effects are garbage; I already feel dirty enough when I have to use $?.
This piece of crap also breaks under the DEBUG trap:
$ debug() {
> :
> }
$ trap debug DEBUG
$ test -e foo && echo $_ exists
debug exists
$ test -e bar && echo $_ exists
!1!
(That !1! is how non-zero exit status is printed in my setup.)Sorry, I'm not going back to a 1978 way of writing shell tests, in order to use some broken magic variable.
Why not?
[ -d /nix ] && echo ... D=/nix test -d $D && echo $D exists … $ V=nada echo "x${V}x"
xx while true; do ...; done
Is `true` a builtin?I might want to avoid an external process call just to create an unconditional loop.
$ echo $BASH_VERSION
4.4.20(1)-release
$ type true
true is a shell builtin
Also: $ type test
test is a shell builtin
$ type [
[ is a shell builtinThat said, [[ being guaranteed to be built-in certainly had its purpose at ages where shell script performance had any kind of relevance, and that was no so long ago.
ifif [[ x == 1 ]] thenthen
echo "x is one"
elseelse
echo "x is not one"
fifi
forfor x in 1 2 3 dodo
echo "x is $x"
donedone
whilewhile [[ x == 1 ]] dodo
echo "x is one"
x=$((x + 1))
donedone
untiluntil [[ x != 1 ]] dodo
echo "x is not one"
donedone
The whole [[ ]] $(( )) ifif fifi dodo thing just seems like they're just doubling down instead of admitting they made a mistake.And if they really wanted [[ ]] to seem like syntax instead of a shell command, they could at least allow it to be used without spaces on each side of it like $(( )) or parens or brackets in any other language. And every other language lets you use as many redundant parens as you like for clarity, without running twice as many commands or producing a syntax error or weird unexpected behavior. But I don't think clarity was ever a design goal with Unix shell scripting languages.
Ahem:
if [ x = 1 ]
then echo "x is one"
else echo "x is not one"
echo "namely, it's $x"
fi
`if [ ] ; then` should only ever be used in one-liners, where there is not a newline after `then`; I'm not sure how that ended up being taught as a way to write multi-line commands (I'd tenatively blame Pascal, but that's probably unfair).