Hacker News new | past | comments | ask | show | jobs | submit login

Taking the last point one step further, we can also dispense with the if block entirely:

    if [ a = b ]; then
        echo "Oops!"
    else
        echo "Expected; phew!"
    fi
becomes

    [ a = b ] && echo "Oops!" || echo "Expected; phew!"
I'm not sure how often you should do this but sometimes it comes in handy for things like

    [ "$debug" ] && echo "what's going on" >&2
to conditionally print debug output to stderr.

----

And the fact that the if block tests a regular command means we can also do things like

    if grep -q 'debug' /var/log/nginx/access.log; then
        echo "Debug request found!"
    fi
----

Something I have not yet bothered to figure out is whether I should write

    [ $(expr 1 + 1) -eq 2 ] && [ $(expr 2 + 2) -eq 3 ]
or use the built in logical and of test:

    [ $(expr 1 + 1) -eq 2 -a $(expr 2 + 2) -eq 4 ]
As long as performance is not a concern, I can see roughly equal reasons in favour of either.



> [ a = b ] && echo "Oops!" || echo "Expected; phew!"

Not to be taken as a general rule though. I might be mistaken but I think that bash would parse the line as:

  ([ a = b ] && echo "Oops!") || echo "Expected; phew!"
so if the command sequence after `&&` fails, then the code sequence after `||` is executed anyway:

  illo@joe:~ $ [ "a" == "a" ] && >/dev/full echo "strings match" || echo "strings don't match"
  -bash: echo: write error: No space left on device
  strings don't match
  illo@joe:~ $
This is different from the semantics of the `if` block:

  illo@joe:~ $ if [ "a" == "a" ]; then >/dev/full echo "strings match"; else echo "strings don't match"; fi
  -bash: echo: write error: No space left on device
  illo@joe:~ $


I'd advise against that kind of shortening. If you use set -e, which you should, then

    if [ a = b ]; then
      echo "Oops!"
    fi
will do exactly what you imagined, but

    [ a = b ] && echo "Oops!"
will quit with an error if expression a does not equal expression b.


No it won't. set -e is implicit disabled for the first command with && and ||. Same for a command after if/while/until and after !. It should only matter if you implicit return immediately after.

  $ bash -ec 'if [ 1 = 2 ]; then echo true; fi; echo $?'
  0
  $ bash -ec '[ 1 = 2 ] && echo true; echo $?'
  1
In both cases it does not quite and execute the last echo.


> Something I have not yet bothered to figure out

According to POSIX, the -a and -o binary primaries and the '(' and ')' operators have been marked obsolescent. See https://pubs.opengroup.org/onlinepubs/9699919799/utilities/t... under "Application Usage".


Regardless of `-a` vs two tests and `&&`, there's no need to shell out to `expr` if bash's arithmetic evaluation is available:

    [ $((1+1)) -eq 2 ]


arithmetic evaluation is ((…)), $((…)) is arithmetic expansion.

There’s no need for test(1) / [(1) or conditional expressions ([[…]]) if you’re doing arithmetic:

if ((1+1 == 2)); then …; fi


Even better, and TIL. Thanks!


The fact that seasoned developers have to discuss how to write 1+1 correctly, says everything you need to know about the language.


I'm going to assume that if one is using [ rather than [[ then one will also want to use expr rather than $(()).


Arithmetic expansion is a feature of all POSIX compliant shells, which furthermore advises against using `expr`. The latter is only needed for non-compliant shells like some legacy implementations of the Bourne shell.


Oh, I did not know that! Thanks.


What's the basis for that assumption? I'm struggling to see a reason to not use the shell for arithmetic, regardless of `/usr/bin/[`, builtin `[` or `[[`.




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

Search: