How to write a very simple wrapper that provides default parameters?

12,516

Solution 1

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
do
    case "${1-}" in
        -in)
            infile="${2-}"
            shift 2
            ;;
        -out)
            outfile="${2-}"
            shift 2
            ;;
        *)
            break
            ;;
    esac
done

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).

Solution 2

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

Solution 3

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.

Solution 4

  • 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)

program=echo
cmd="$program $*"

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

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

echo
echo "execute result:"
$cmd

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

Note

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

./script -in new\ document.txt
Share:
12,516

Related videos on Youtube

Tobias Kienzler
Author by

Tobias Kienzler

Physicist.

Updated on September 18, 2022

Comments

  • Tobias Kienzler
    Tobias Kienzler almost 2 years

    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.

  • Tobias Kienzler
    Tobias Kienzler over 11 years
    Using $1 etc will fail if I omit parameters, and manually parsing them would be annoying. Is there no midway between that and getopt?
  • Tobias Kienzler
    Tobias Kienzler over 11 years
    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...
  • Tobias Kienzler
    Tobias Kienzler over 11 years
    Neat! I think the quotes issue can be solved by using $@ instead of $*. What does ${*#*$param} do?
  • Tobias Kienzler
    Tobias Kienzler over 11 years
    Of course I could also simply write a python script...
  • LiuYan 刘研
    LiuYan 刘研 over 11 years
    @TobiasKienzler, "${*#*$param}" == "$*" is used to check if $* NOT contains $param, it's Remove Smallest Prefix Pattern parameter expansion.
  • Stéphane Chazelas
    Stéphane Chazelas over 11 years
    ./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.