4 ms·
Taking the last point one step further, we can also dispense with the if block entirely: if [ a = b ]; then echo "Oops!" else echo "Exp
by kqr 3y ago
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.
- illo 3y ago> [ 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:~ $
- deleted 3y ago[deleted]
- nwellnhof 3y ago> 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/test.html https://pubs.opengroup.org/onlinepubs/9699919799/utilities/t... under "Application Usage".
- darrenf 3y agoRegardless 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 ]
- kqr 3y agoI'm going to assume that if one is using [ rather than [[ then one will also want to use expr rather than $(()).
- ykonstant 3y agoArithmetic 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.
- kqr 3y agoOh, I did not know that! Thanks.
- darrenf 3y agoWhat'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 `[[`.
- neuromanser 3y agoarithmetic 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
- darrenf 3y agoEven better, and TIL. Thanks!
- 3y ago
- cesnja 3y agoI'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.
- Calzifer 3y agoNo 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.