6

Let's say I have this simple code:

echo "Are there any arguments?"
if [ $# -eq 0 ]; then
    echo "false"
else
    echo "true"
fi

As you can see it would be better to just have opportunity to directly print condition result, but I don't know how to do it.

It would be something like:

echo "$([ $# -eq 0 ])"

But it doesn't work that way. Can we do this without if?

  • You can try zsh. Zsh will change PS1 color (command prompt color) according to $?(the return value of the last command). imgur.com/a/yBz2H – Weekend Aug 10 '17 at 16:04
9

In this case you can use the list control operators && and || instead:

[[ $# -eq 0 ]] && echo false || echo true
[[ $# -eq 0 ]] && { echo false; } || { echo true; }

The { } group a list of commands, you don't need them for just a single command, but they often make such constructions more readable (though a list also requires a terminating ; or newline).

As noted by @Kusalananda, this works for simple code (like echo) where commands return 0 ("true"): despite the lexical similarity the above does not have the same semantics as a short-circuited evaluation in C does, i.e.:

(argc==1) && printf("false\n") || printf("true\n");

A workaround where the command(s) might return a non-zero status is:

[[ $# -eq 0 ]] && { echo false;:; } || { echo true; }

where the extra ":" null command at the end of the first list ensures that it returns a 0 (true) status (the return status of a list is the exit status of the last command executed in the list).


When you have two (or another defined number of states), you can also use an array with a computed index, as shown in Stéphane's answer:

declare -a bool=([1]=true [0]=false)
echo ${bool[ (($# == 0)) ]}

or

temperature=70
declare -a porridge=([1]="too hot" [2]="just right" [3]="too cold")
echo ${porridge[ (( temperature >= 75 ? 1 :
                    temperature <= 68 ? 3 : 2 )) ]}

This uses arithmetic expressions within (( )), where 0 is false, opposite to the usual shell convention.

  • 1
    But note that the semantics of the statements are slightly altered by this. The last command will be executed if either of the previous commands returned a non-zero exit status. This means that using ... && ... || ... is not generally a good replacement for if ...; then ...; else ...; fi. – Kusalananda Feb 24 '19 at 8:32
2

You can use $? that keeps the exit code of the last executed command:

echo "Are there any arguments?"
[ $# -eq 0 ]
echo $?
2

You can do something like:

bool=(false true)
echo "${bool[$# != 0]}"

(assuming ksh93, bash or zsh in ksh emulation).

In any POSIX shell,

echo "$(($# != 0))"

will output 1 for true and 0 for false.

0

Since I can't post comments yet (insufficient rep), I'll point out in a new answer that mr-spuratic's solution also works with single brackets, like so:

[ $# -eq 0 ] && { echo false; } || { echo true; }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.