I've come across a bash script which runs the following command within a function
set -e
rm -rf some_dir/* && :;
What is the purpose of && :;
in this context?
Edit:
I understand that it's synonym to && true
, but now I don't undertand why it bypass set -e
Trying it out I see that running the following
#!/bin/bash -e
# false
echo false alone return 1 and fail with -e
false || true
echo "false || true return $?"
false || :;
echo "false || :; return $?"
false && true
echo "false && true return $?"
false && :;
echo "false && :; return $?"
false && :
echo "false && : return $?"
Outputs
false alone return 1 and fail with -e
false || true return 0
false || :; return 0
false && true return 1
false && :; return 1
false && : return 1
The reason it suppresses the effect of set -e
can be found in the man page:
-e Exit immediately if a simple command (see SHELL GRAMMAR above) exits with a non-zero status.
The shell does not exit if the command that fails is part of the command list immediately
following a while or until keyword, part of the test in an if statement, part of a && or ||
list, or if the command's return value is being inverted via !. A trap on ERR, if set, is
executed before the shell exits.
For emphasis: The shell does not exit if the command that fails is ... part of a && or || list
The shell does not exit if the command that fails is ... part of a && or || list
Note that there is some subtlety here. A common error is to write code like foo() { ...; rm path; #cleanup }
foo() { ...; rm path; #cleanup }
foo() { ...; rm path; #cleanup }
in which the intent is to always be successful. By which I mean that the author of the code didn't really even think about the exit status of foo
but implicitly expects is to succeed and doesn't care about the exit status of rm
, forgetting that foo
returns the exit status of rm
. The code might be re-written rm path || :
rm path || :
to ensure that foo
always returns successfully, or rm path && :
to return the status of rm
but not exit if errexit
is enabled. Frankly, it's too subtle and I believe one additional reason for never using set -e
. Also, an argument could be made that you should never rely on the exit status of code unless you explicitly exit
a script or return
from a function.
The &&
is easy to explain. From the bash man
page:
command1 && command2
command2 is executed if, and only if, command1 returns an exit status of zero.
:
is harder to find in the docs. :
is a builtin that is equivalent to true
:
:; echo $?
0
So overall, this command equates to:
Recursively remove the directory, and if the rm is successful, run 'true'.
It's seems unnecessary though, since &&
has already 'tested' that rm is returning true, so it's a bit like doing true && true
.
More commonly this is used when you want an if/else
where only the else
does something, eg
if command1; then :; else command2; fi
Though this is only useful if your system doesn't have a true
command, which is arguably easier for a later reader of the code to understand. (Or you could use a negative test and not bother with a no-op at all).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.