35

I have a script running on Linux that accepts some parameters.
I would like to do something like:

if [[ $CONDITION == "true" ]]; then  
  script param1 --param2  
else
  script param1  
fi 

I would like to avoid the forking path of the if.
Is there a more optimal way to pass the second parameter?

9
  • 1
    Where is this if? In the script itself? In another script that calls the target script? Are these options (--param2) or arguments (param1)? Please edit your question and give us more details.
    – terdon
    May 30, 2018 at 8:17
  • One other note: true is a shell builtin that returns a success exit status. If you use CONDITION=false when CONDITION is not true, then you could write: if "$CONDITION"; then echo yes; fi or "$CONDITION" && echo yes May 30, 2018 at 19:21
  • @glennjackman:The true is not the same as "true" right?
    – Jim
    May 30, 2018 at 20:40
  • They are the same: gnu.org/software/bash/manual/bash.html#Quote-Removal -- you can execute the command "echo" "foo" with no difficulty because the shell will remove the quotes before executing the command. May 30, 2018 at 20:44
  • For example I often do valid=false if someCondition; then valid=true; fi; if ! $valid; then echo Invalid; exit 1; fi May 30, 2018 at 20:47

3 Answers 3

55

The most expansible and robust way would probably be to use an array to hold the optional parameter(s):

params=()
if [[ $CONDITION == true ]]; then
    params+=(--param2)
fi
script param1 "${params[@]}"

Or in shorthand:

[[ $CONDITION == true ]] && params+=(--param2)
script param1 "${params[@]}"

That avoids repeating the constant part of the command and you can put more than one argument in the array, even the whole command.

Note that it's important to do this with an array: if you replace the array with a regular variable (params="--param2"; script param1 $params) you'll either have to expand the variable unquoted, with all the problems that brings, or expand it quoted, in which case you'll pass an empty string as argument if the variable is empty.

In a simple case like this, the "alternate value" expansion can also be used:

cond=x
p2="--param2"
script param1 ${cond:+"$p2"}

Here, if cond is nonempty (regardless of if it's cond=false or cond=0 instead of cond=true), the value of p2 is expanded. This may be seen as less ugly than arrays, but be careful with the placement of the quotes.

See also:

5
  • it should be noted that this is passing in part the literal string --, and not the unary -- operator
    – Zombo
    May 30, 2018 at 18:22
  • 1
    @StevenPenny, well, the whole idea of a -- operator only exists in the shell within arithmetic expansions, and there aren't any here. I can't think of any special meaning for the dash in the shell outside of them, either.
    – ilkkachu
    May 30, 2018 at 18:39
  • @ilkkachu how can you do this in one line? script param1 ${[[ $CONDITION == true ]] && params+=(--param2)} ? Apr 15, 2020 at 16:37
  • @Turnipdabeets, do you mean something like this? par="x y"; printf ":%s\n" a b ${par+"$par"} It should expand par as another argument after b, if par is set (i.e. unset par; printf ":%s\n" a b ${par+"$par"} there would not be an empty argument after b). Or you could have ${cond:+"$par"} to expand par if cond is non-empty.
    – ilkkachu
    Apr 17, 2020 at 17:40
  • Is there a way to make it work with set -o nounset when the params variable is empty ? I'm getting "unbound variable" errors. EDIT : use "${params[@]-}" with a dash at the end prevents the problem Nov 29, 2022 at 13:10
9

A versatile way to do this is to set the arguments in an array. The most basic array is the list of positional parameters defined with set. You can build the list of parameters in sequence.

set -- param1
if [[ $CONDITION == "true" ]]; then  
    set -- "$@" --param2  
fi 

command "$@"  

Which could be reduced to:

set -- param1
[[ $CONDITION == "true" ]] && set -- "$@" --param2
command "$@"  

If the list of positional parameters needs to be preserved, then either:

  • Use a function:

    callcommand(){     set -- param1
                       [[ $CONDITION == "true" ]] && set -- "$@" --param2
                       command "$@"       
                 }
    callcommand
    
  • Or use some other array variable:

    paramArray=()
    paramArray+=(param1)
    [[ $CONDITION == "true" ]] && paramArray+=( "--param2" )
    command "${paramArray[@]}"
    
2
  • I don't really understand this. param1 is already a parameter. Does this change the parameter array of the script?
    – Jim
    May 31, 2018 at 20:48
  • @Jim No, param1 is not an argument of the script code above, it become a parameter of the command called. Yes, the positional parameters are changed (as they are used). See some alternatives in the edited answer.
    – user232326
    Jun 1, 2018 at 6:53
-1
PARAMS+=" param1"
if [[ $CONDITION == "true" ]]; then  
  PARAMS+=" --param2"
fi
script ${PARAMS}
2

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .