115

I'm looking a way to build conditional assignments in bash:

In Java it looks like this:

int variable= (condition) ? 1 : 0;
1
  • In case the condition involves test, [[ or [ see this question Commented Nov 21, 2022 at 12:52

8 Answers 8

93

If you want a way to define defaults in a shell script, use code like this:

: ${VAR:="default"}

Yes, the line begins with ':' — it is a built-in command which ignores its arguments. I use this in shell scripts so I can override variables in ENV, or use the default.

This is related because this is my most common use case for that kind of logic. ;]

Sign up to request clarification or add additional context in comments.

5 Comments

This is a valuable technique, but the only condition supported with the ':=' notation is 'set to "default" if value is unset or empty'. The more general notation in the question is supported directly in bash.
I agree completely, I gave it a disclaimer for being slightly off topic.
Omitting the colon before equal tests only for the variable to be unset and doesn't change it if it's null.
Related useful explanation about starting with a colon and the parameter expansion in this answer.
This will not work if you're trying to assign default value to a parameter of a function. E.g. ${2:="some value"} will fail.
88

As per Jonathan's comment:

variable=$(( 1 == 1 ? 1 : 0 ))  

EDIT:

I revised the original answer which just echo'd the value of the condition operator, it didn't actually show any assignment.

5 Comments

Nit-pick: that isn't an assignment - it is just a conditional expression. However, variable=$(( 1 == 1 ? 1 : 0 )) works as long as there are no spaces around the first '=' sign; you can omit all the spaces after that and it also works - but think about readability.
You can have complete freedom of spacing (and drop the dollar sign) if you move the opening double parentheses all the way to the left. (( variable = 1 == 1 ? 1 : 0 )) or (( variable = (1 == 1) ? 1 : 0 )) But it could be argued that it's more readable as given in the answer.
Also, it should be noted that this operator only works for arithmetic operations in Bash.
What if the variable I want to set is a string?
This does not work for strings: echo $(( 1 == 1 ? 'hello' : 'world' ))
62

I wanted to do a conditional assignment with strings and I ended up with:

VAR=$([ "$MYVALUE" = "value" ] && echo "YES" || echo "NO")

Which is:

VAR=$([ condition ] && value_when_true || value_when_false)

6 Comments

one line beauty!
This results in nothing be assigned to the variables?
@DouglasGaskell You can it assigns if you run it and echo $VAR
this answer uses a the condition and output of a very slow subshell - way faster approaches are provided in the answers by Kevin Little or Demosthenex
|
54
myvar="default" && [[ <some_condition_is_true> ]]  && myvar="non-default"

real examples:

DELIM="" && [[ "$APP_ENV_RESOLVED" != "" ]] && DELIM=$INNER_DELIM

The condition can be "(( ... ))" as well:

filepath=/proc/drbd && (( $# > 0 )) && filepath=$1

2 Comments

Note that this will misbehave if the first assignment uses command substitution and the command fails. For example, myvar="$(echo 'condition is false'; false)" && true && myvar='condition is true' will set myvar to condition is false instead of condition is true. Fortunately, that's easy to fix: just change the first && to ;.
40

In addition to the other more general answers (particularly as per Jonathan's comment and Kevin's more general answer [which also supports strings]) I'd like to add the following two solutions:


setting the variable to either 0 or 1 based on the condition:

(as the question's example suggests.)

The general form would read

(condition); variable=$?;

where $variable results in being either 0 or 1 and condition can be any valid conditional expression.

E.g. checking a variable ...

[[ $variableToCheck == "$othervariable, string or number to match" ]]
variable=$?

... or checking a file's existence ...

[ -f "$filepath" ]
fileExists=$?

... or checking the nummerical value of $myNumber:

(( myNumber >= 1000000000 ))
is_huge_number=$?


The advantages of this solution is that

  • it supports arbitrary conditional expressions, including strings
    (which are not supported in arithmetic expressions of Jonathan's solution)
  • that variable gets declared in any case, unlike in griffon's answer:
    [ -z "$variable" ] && variable="defaultValue"
    Which would matter in case you want to nameref it later on (e.g. from within a function).


Please note: In Bash, the special variable $? always contains the exit code of the previously executed statement (or statement block; see the man bash for more details). As such, a positive result is generally represented by the value 0, not 1 (See my comment below, thanks Assimilater for pointing it out). Thus, if the condition is true (e.g [[2 eq 2]]) then $?=0.

If instead you need 0 or 1 in your variable (e.g. to print or do mathematical calculations) then you need to employ boolean negation using a leading exclamation mark (as pointed out by GypsySpellweaver in the comments below): ( ! condition ); variable=$? or ! ( condition ); variable=$?. (However, readability in terms of what happens might be a bit less obvious.)

Another possible solution by Jonathan would be variable=$(( 1 == 1 ? 1 : 0 )) - which, however, is creating a subshell.

If you want to avoid the creation of a subshel, keep good readability or have arbitrary conditions, use one of the following solutions.


setting the variable to arbitrary values:

as it is done in most other answers, it could adapted as follows:

(condition) \
    && variable=true \
    || variable=false

e.g as in

[[ $variableToCheck == "$othervariable, string or number to match" ]] \
    && variable="$valueIfTrue" \
    || variable="$valueIfFalse"

or to get 1 in a positive check, and 0 upon failure (like in the question's example):

[[ $variableToCheck == "$othervariable, string or number to match" ]] \
    && variable=1 \
    || variable=0

(for the last example, - as already mentioned in the notes above - the same can be achieved with boolean negation using a leading exclamation mark:

[[ ! $variableToCheck == "$othervariable, string or number to match" ]]
variable=$?


The advantages of this solution is that

  • it might be considered a bit better readable than Kevin's answer
    myvar="default" && [[ <some_condition_is_true> ]] && myvar="non-default", and
  • the $valueIfTrue is conditionally evaluated only if needed,
    which would matter in case you'd do something
    • with side-effect, like
      • variable=$((i++)), or
      • { variable=$1; shift; }
    • high computation, like
      • variable=$(find / -type f -name ListOfFilesWithThisNameOnMySystem)
  • is a bit shorter than ghostdog74's answer
    (which, however is great if you have multiple conditions!)
  • does not open a subshell as in Pierre's answer
  • and as above:
    • it supports arbitrary conditional expressions, including strings
      (which are not supported in arithmetic expressions of Jonathan's solution)
    • that variable gets declared in any case, unlike in griffon's answer:
      [ -z "$variable" ] && variable="defaultValue"
      Which would matter in case you want to nameref it later on (e.g. from within a function).

12 Comments

The result of your first solution is a little confusing to me. A conditional that evaluates to true results in a value of 0; where a conditional that evaluates to false results in a value of 1
Maybe I did it wrong though. I test with [ "$1" == "--all" ] ; allperiods=$? ; echo $allperiods
@Assimilater, I agree, that 0 and 1 might be confusing. It stems from the fact that an exit code of a program or statement is usually 0 when everything went ok, and an arbitrary code (usually between 1 and 254) for errors. Thus executable && executesWhenOk || executesWhenNotOk and in our scenario the test is the "executable" (or statement, to be precise), and the special variable $? contains the result code of the last statement. hope that helps clarifying.
That helps :) (You might consider adding it to the answer ;) )
The "normal" Boolean logic which programmers are adapted to, of 1 is true and 0 is false, can easily be achieved in this case with the NOT ! operator applied to the expression. Either inside, or outside the 'expression'. ( ! condition ); variable=$? or ! ( condition ); variable=$? Such that [ ! -f "$filepath" ]; fileExists=$? works as a programmer would be accustomed to: 1 file exists, and 0 file is missing.
|
14

Big ups to @Demosthenex and especially @Dennis Williamson for the shortest and easiest solution I've seen. Leave it to bash to require a bunch of parentheses for a simple ternary assignment. Ahh, the 60s! And to put it all together in an example...

echo $BASHRULES;             # not defined
                             # no output
: ${BASHRULES:="SCHOOL"}     # assign the variable
echo $BASHRULES              # check it
SCHOOL                       # correct answer
: ${BASHRULES="FOREVER?"}    # notice the slightly different syntax for the conditional assignment
echo $BASHRULES              # let's see what happened!
SCHOOL                       # unchanged! (it was already defined)

I wrote that a long time ago.. these days I'd probably get more excited over a solution like...

PLATFORM=iphonesimulator
OTHERSDK=iphone && [[ $PLATFORM=~os ]]      \
                &&     OTHERSDK+=simulator  \
                ||     OTHERSDK+=os

$OTHERSDKiphoneos

4 Comments

Thank you, Mr. @alex gray. This is an excellent syntactic arrow that everyone should have in their bash quiver… for the curious and/or unadventurous who discover it here, this sort of conditional assignment plays nice with export statements, too – which you put that between the colon prefix and the dollar-sign statement-y part, e.g. : export ${YO_DOGG:="global environment default"}
Your second solution, actually represents the second solution of my answer and was added only after I've posted it. A short reference would have been nice. Please also note, since iphonesimulator does not contain the string os, above solution would end up with OTHERSDK=iphonesimulator.
I like this short answer. Some of the others were too long.
The Bourne shell was created in the late 1970s, and Bash in the late 1980s.
6

another way using a case/switch

case "$variable" in
  condition) result=1 ;;
          *) result=0 ;;
esac

Comments

5

If you want to assign a value unless variable is empty use this:

[ -z "$variable" ] && variable="defaultValue"

You can put as well, each other condition on the []

1 Comment

Variable expansion is meant to handle this as follow : ${variable:='defaultValue'}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.