简体   繁体   中英

What is the purpose of && :; in bash scripts

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM