Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Your comment makes no sense. GNU Coreutils has a "man [" as well as "man test" man page.

Bash has "help test" for a quick cheatsheet.

The [ command is very old; it was already present in Version 7 Unix in 1979.



I think GP's point was that `[` feels like syntax, but - importantly - isn't.

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.)


Parts of the comment make a LOT of sense actually, when you look at shell scripts written by the uninitated. Often times, I see constructs like

    while [ 1 ]; do ...; done
which are a pretty clear indication of the author's misconception about the perceived nature of [ ], I think.


The nice way to write that isn't any kind of test command but:

   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.


> There is never any reason to use test

What's the reason for always using [ ?


I bet that most code uses [ or [[, if I am right, then reasoning is: “it is the normal usage”.

(Making life easier for others and your self)


So my scripts look normal, like everyone else's.


> There is never any reason to use test

    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.)


It's not working for me in a non-interactive Bash script on Bash 4.4.

$_ 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.


Wow, I wasn’t aware of all these shortcomings! I will stop using it in my scripts too.


> You cannot do this with [

Why not?

  [ -d /nix ] && echo ...


As '$_' is set to last arg of previous run command, the test example will have it be the name of directory whereas for [ will always be ].


  D=/nix test -d $D && echo $D exists …


  $ V=nada echo "x${V}x"
  xx


V=nada; echo "x${V}x"


Ah yes, now I see it.


    while true; do ...; done
Is `true` a builtin?

I might want to avoid an external process call just to create an unconditional loop.


POSIX allows any command to be a builtin, as long as a real external command is also available which can be executed via execv and whatnot.

  $ 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 builtin


Note that bash implements [ as a builtin so the coreutils man page might not match exactly.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: