-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Add warning about shorter if
and &&
#127
base: master
Are you sure you want to change the base?
Conversation
Definitely nice to use `&&` as a shorter `if`, but there are caveats, when using `&&` in a function.
} | ||
|
||
func_example2() { | ||
[ $1 -gt 11 ] && return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this use case one should explicitly supply exit code to return
, so that it doesn't use last command's (test
) exit status by default. And this is what the difference between the two constructions is. So that's kind of NOT unexpected result. See help return
. I think this should be mentioned in this snippet to clarify what the "unexpected result" means, alongside the proper usage.
Another example of why this is a good warning that always bites me is when you're working with scripts that use ❯ ( set -e ; func_example1 10; echo after ); echo $?
after
0
❯ ( set -e ; func_example2 10; echo after ); echo $?
1 As you can see, because |
@bradrf Basically the "correct" function used as an example in this PR is sort of weird since it returns success in both cases despite arg is greater than 11 or not. Meaning that this lacks error handling and hence the "bug". That is why such snippet suggested in this PR should better be supplied with an example of proper use. E.g.
What I mean is there's no error or improper use, but the lack of proficiency and experience 😉 |
I wanted to update the Important note: using the I use &&, ||, brace, and paren exclusively. I never use if/then and I'm familiar with the regular behavior, so when I read "unexpected results" I am confused about what is being pointed out, it's all as expected--as far as I can see. Could there be some more verbosity about what is being demonstrated here? If that is unexpected... I think there is some (not-necessarily true) assumptions about what is expected??? Also regarding option errexit, that can get messy in your shell prompt environment. If you are creating functions for use on your shell prompt, parenthetical functions can be more optimal then the bracketed ones, eg we have the same directory on errexit even if pwd has been changed within the function. Paren functions inherit exported variables, but since it is a subshell, all set variables are basically local. There is a performance hit with paren functions as well. subshell_function () ( # subshell sets pipefail, errexit and PWD, only within the function set -o errexit # Exit on command non-zero status set -o pipefail # exit pipeline on non-zero status set -o errtrace # any trap on ERR is inherited by shell functions set -o functrace # traps on DEBUG and RETURN are inherited by shell functions cd /tmp false true ) This function doesn't reach the true statement, it returns status 1, the pwd and original environment are unchanged. However if braces were used, the shell prompt would exit, fix that and PWD would change when the function is called. |
BTW - this prompt prints the status of prior command, iff it is non-zero, handy! export PS1="\${?%0} \u@\h:\w " and here is an unexpected behavior for me :-) if I set p="-3" then test if the string is set... error. I get the desired result with set p=-3.0 t= p=-5 f= [ "$t" -o "$p" -o "$f" ] && echo y || echo n -bash: [: -5: unary operator expected n expr "$p" : '^-[[:digit:]]*$' >/dev/null && p="${p}.0" [ "$t" -o "$p" -o "$f" ] && echo y || echo n y |
Definitely nice to use
&&
as a shorterif
, but there are caveats,when using
&&
in a function.This is probably the single largest error I used to make. It took me far too long to remember this.