Given a program that requires some parameters, e.g. program -in file.in -out file.out, what would be the simple-most approach to write a bash script that could be called with or without any of these parameters and use default values for each?

script -in otherfile would run program -in otherfile -out file.out,
script -out otherout -furtherswitch would run program -in file.in -out otherout -furtherswitch etc.

4 Answers 4


A default value is easy to define in Bash:

foo="${bar-default}" # Sets foo to the value of $bar if defined, "default" otherwise
foo="${bar:-default}" # Sets foo to the value of $bar if defined or empty, "default" otherwise

To process your parameters, you can use a simple loop:

while true
    case "${1-}" in
            shift 2
            shift 2

program -in "${infile-otherfile}" -out "${outfile-otherout}" "$@"

Useful reads:

I also recommend using getopt instead, because it is able to handle many special cases which would very quickly complicate and clutter your code (Non-trivial example).

  • Thanks! A while $# -gt 0 (or similar) and *) others="${others-} $1"; shift 1 ;; would survive other parameters before the default-able ones. But maybe I should learn getopt instead... Feb 7, 2013 at 11:12
  • Of course I could also simply write a python script... Feb 7, 2013 at 11:24

l0b0's answer shows how to set a default value through assignment and checking another variable's state (although, of course, you can also do this operating on the same variable you are assigning to), but there is a more concise way to do the same thing:

: "${foo=bar}" # $foo = bar if $foo is unset
: "${foo:=bar}" # $foo = bar if $foo is unset or empty
  • Pass all parameters ($*) passed to script to program too
  • Check each parameter you interested, if it's already in parameters passed, then ignore it. otherwise use default parameter value

Sample code

interested_parameter_names=(-in -out)
default_parameter_values=(file.in file.out)

cmd="$program $*"

for ((index=0; index<${#interested_parameter_names[*]}; index++))
    if [ "${*#*$param}" == "$*" ]   # if $* not contains $param
        cmd="$cmd $param $default_value"

echo "command line will be:"
echo "$cmd"

echo "execute result:"

You can easily add more default parameters/values by add more array element in $interested_parameter_names and $default_parameter_values

Sample output

$ ./wrapper.sh -in non-default.txt -other-params
command line will be:
echo -in non-default.txt -other-params -out file.out

execute result:
-in non-default.txt -other-params -out file.out


When passing parameters which contains space, it should be escaped by \, not just quoted them. Example:

./script -in new\ document.txt
  • Neat! I think the quotes issue can be solved by using $@ instead of $*. What does ${*#*$param} do? Feb 7, 2013 at 11:23
  • @TobiasKienzler, "${*#*$param}" == "$*" is used to check if $* NOT contains $param, it's Remove Smallest Prefix Pattern parameter expansion. Feb 7, 2013 at 11:28
  • 1
    ./script -in new\ document.txt would not work, and there's not way to make it work with that flawed approach. By concatenating the arguments into a string, you're losing the information about how those arguments are separated. Feb 7, 2013 at 13:02

You have two ways, as usual, simple and hard. Simple is to use inner variables, for example

program -in otherfile -out file.out

Here variable are

$0 = The script name
$1 = -in
$2 = otherfile, etc.

The Hard way is to use getopt, more information you can find here.

  • Using $1 etc will fail if I omit parameters, and manually parsing them would be annoying. Is there no midway between that and getopt? Feb 7, 2013 at 10:23

You must log in to answer this question.

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