13

For example, if I have script ./foo that takes 10 parameters, and I only want to pass the 8th parameter. The only way I know how to do this currently is:

./foo '' '' '' '' '' '' '' 'bar'

Is there an easier/better way?

1
  • 1
    This is why programs usually use options rather than positional parameters if you have lots of parameters.
    – Barmar
    Sep 10, 2014 at 19:18

2 Answers 2

18

Assuming you can change the the script, you should consider using optional parameters (options) instead of required parameters (arguments).

If you have each of the first 7 seven parameters as options, and have them default to the empty string then you could just do:

./foo bar

If you use a POSIX-compatible shell you can use the getopts utility, or the program getopt. bash - like most shells - offers getopts as a built-in. Either way is easier than rolling your own command-line parser.

Unless you implement something like the last X non-option arguments are the values for the last Y arguments and X-Y option arguments you have to provide option strings before each of the 7 (now empty) strings if you want to set any of those. This however is not common practise, normally an option is always an option and an argument an argument, and the order of option "insertion" is free.

1
  • 5
    +1 for getopt(s). Positional parameters are a sad time, and should be avoided.
    – HalosGhost
    Sep 7, 2014 at 15:04
4

Another way to do this thing is to name the parameter you want to declare and then do so:

{   cat >./foo 
    chmod +x ./foo
    eight=declared ./foo
    eight=declared_and_preferred \
        ./foo 1 2 3 4 5 6 7 8
    ./foo 1 2 3 4 5 6 7 8
    ./foo
} <<\SCRIPT
#!/usr/bin/sh
: ${eight:=${8:-some_default}}
printf '$eight = %s\n' "$eight"
#END
SCRIPT

OUTPUT

$eight = declared
$eight = declared_and_preferred
$eight = 8
$eight = some_default

In the above example the explicitly declared environment variable is preferred to the command-line argument, but the command-line argument is used when the environment variable is either empty or unset. When both the 8th positional and the environment variable $eight are empty or unset the default value some_default is assigned to $eight. In either case the : can be removed from the :- or := statements if empty should be an acceptable value.

The variable $eight could as well have been set like:

printf '$eight = %s\n' "${eight:=${8:-some_default}}"

... and the previous line omitted entirely but I wanted to demonstrate that declaring a variable in that way does result in a persistent value, and so I did it in two commands. Either way $eight is set to the final value of that compound parameter expansion.

getopts - for robust scripts - often is the best way to handle command options. Positional parameters, on the other hand, are almost always the most simple means of robustly handling operands in a script.

For example:

touch file$(seq -ws\ file 100)
./foo *

OUTPUT

$eight = file008

There we only see the eighth operand, but there are 101 of them globbed from my test directory.

You must log in to answer this question.

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