40

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. Commented 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 Commented May 30, 2018 at 19:21
  • @glennjackman:The true is not the same as "true" right? Commented 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. Commented 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 Commented May 30, 2018 at 20:47

3 Answers 3

63

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 Commented 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. Commented May 30, 2018 at 18:39
  • @ilkkachu how can you do this in one line? script param1 ${[[ $CONDITION == true ]] && params+=(--param2)} ? Commented 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. Commented 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 Commented Nov 29, 2022 at 13:10
10

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? Commented 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. Commented 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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.