What command means "do nothing" in a conditional in Bash?
Asked Answered
F

5

285

Sometimes when making conditionals, I need the code to do nothing, e.g., here, I want Bash to do nothing when $a is greater than "10", print "1" if $a is less than "5", otherwise, print "2":

if [ "$a" -ge 10 ]
then
elif [ "$a" -le 5 ]
then
    echo "1"
else
    echo "2"
fi

This makes an error though. Is there a command which will do nothing and also not slow down my script?

Frayne answered 11/7, 2013 at 1:24 Comment(3)
echo $[a<=5?1:2] a brief ternary does it, ignoring any test for a>=10Kiosk
@roblogic, why would you use ancient/deprecated/nonstandard ksh syntax when there are standardized options ($((a <= 5 ? 1 : 2))) available?Opprobrium
$[] is supported in bash, but yes $(()) is probably better. I like to be brief.Kiosk
S
533

The no-op command in shell is : (colon).

if [ "$a" -ge 10 ]
then
    :
elif [ "$a" -le 5 ]
then
    echo "1"
else
    echo "2"
fi

From the bash manual:

: (a colon)
Do nothing beyond expanding arguments and performing redirections. The return status is zero.

Saporific answered 11/7, 2013 at 1:26 Comment(10)
@SaintHax No, it doesn't run true. It's built into the shell, and does nothing.Saporific
it is shell built in (you are correct), it returns true (status 0) just like true does, and it is more difficult to read. Bash is a DevOps language, and if : is written by someone on my team, I'd have them change it.Dynameter
@Dynameter If someone used true in a non-conditional context, I'd have them change it. if true is fine, then true seems wrong.Saporific
Of course, you can simply rewrite the code to use if ! condition; then do something; fi instead of if condition; then :; else do something; fi.Saporific
I agree with you. This example could be written if/elif/else using compound conditions and would be better.Dynameter
@Saporific maybe it's usefull in this case while (condition) do : doneEchinoderm
@Echinoderm The code is not on a loop, hence while <cond> is not usefulNevil
@Nevil of course not in this specific case (here you can avoid : by using the code proposed by barmar), but more generally, if you need to wait until a condition is false, you can use the while (condition) do : doneEchinoderm
E.g. while ! ping -c 1 hostname; do : done to wait for ping to succeed. @EchinodermSaporific
(err, do :; done, there -- : doesn't get special parsing rules, it still needs to be terminated with a newline or other command separator)Opprobrium
S
63

You can probably just use the true command:

if [ "$a" -ge 10 ]; then
    true
elif [ "$a" -le 5 ]; then
    echo "1"
else
    echo "2"
fi

An alternative, in your example case (but not necessarily everywhere) is to re-order your if/else:

if [ "$a" -le 5 ]; then
    echo "1"
elif [ "$a" -lt 10 ]; then
    echo "2"
fi
Sclerous answered 11/7, 2013 at 1:26 Comment(4)
If you don't test the result both true and false are effectively no-ops as far as the script is concerned, but in principle they could fork in some shells that accept this syntax so perhaps : is better.Kirby
The question is tagged bash. In bash, true and false are built-ins. For older shells, true, false, and even : might be external commands (though you'd probably see the latter only in very old shells).Joyejoyful
I prefer : simply because it is more explicit what the intent isBawl
The result false may not be a no-op, because if set -e is used (exit on non-zero) then false will cause the script to exit immediately. true is a better no-op. : is a real no-op, but I have to agree that it is unreadable and I've been programming bash for 30 years and I didn't know about it...Tezel
G
12

Although I'm not answering the original question concering the no-op command, many (if not most) problems when one may think "in this branch I have to do nothing" can be bypassed by simply restructuring the logic so that this branch won't occur.

I try to give a general rule by using the OPs example

do nothing when $a is greater than "10", print "1" if $a is less than "5", otherwise, print "2"

we have to avoid a branch where $a gets more than 10, so $a < 10 as a general condition can be applied to every other, following condition.

In general terms, when you say do nothing when X, then rephrase it as avoid a branch where X. Usually you can make the avoidance happen by simply negating X and applying it to all other conditions.

So the OPs example with the rule applied may be restructured as:

if [ "$a" -lt 10 ] && [ "$a" -le 5 ]
then
    echo "1"
elif [ "$a" -lt 10 ]
then
    echo "2"
fi

Just a variation of the above, enclosing everything in the $a < 10 condition:

if [ "$a" -lt 10 ]
then
    if [ "$a" -le 5 ]
    then
        echo "1"
    else
        echo "2"
    fi
fi

(For this specific example @Flimzys restructuring is certainly better, but I wanted to give a general rule for all the people searching how to do nothing.)

Ginseng answered 12/1, 2014 at 4:30 Comment(2)
One reason someone might want to have a no-op is when initially structuring the code with the idea that one will add the "add something here later" without having inadvertent side effects. E.g. if one is putting an if-then-else-fi in a .bashrc, if you put echo "put stuff here" it'll break some of the non-login uses (e.g. scp gets broken), and only whitespace/comments causes a runtime error.Periclean
Also, personally, I prefer to write code that is more "human friendly". It's often possible to restructure code to be more concise or even efficient. But when that's not critical, I prefer my code to be more readable for whichever developer comes along afterwards. (I also like commenting my code.)Chubby
A
1

It looks like that there is no other way than writing your own nop as a function. : does not the intended job, as it affects the exit status; maybe you'll find a builtin in the manual that does not change the exit status, but I've failed to exhibit such a one. You may say:

nop() { return; } # may return $?
bad() { return 42; }

bad; nop; echo $? # "nop" does nothing and keeps status; echo echoes 42
bad; :  ; echo $? # ":" does nothing but changes status; echo echoes 0
Angrist answered 12/3 at 16:51 Comment(0)
B
0

instead of :, true, false I use

echo -n ""

It avoid empty line in terminal

You could also do it more concisely as:

echo -n
Babur answered 15/2, 2023 at 20:3 Comment(1)
echo -n is listed in the POSIX specification as explicitly undefined behavior (see the APPLICATION USAGE section of pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html spelling this out), and even if you 100% know your shell is bash, it still can change behavior on runtime flags (see shopt -s xpg_echo and how its behavior meshes with set -o posix -- moreover, both those flags can be set by environment variables even if your code never actually runs them).Opprobrium

© 2022 - 2024 — McMap. All rights reserved.