For any serious shell script, you are likely to have two kinds of arguments—options that modify the behavior of the script and the real arguments with which you want to work. You need a way to get rid of the option argument(s) after you’ve processed them.
Remember this script:
for FN in "$@" do echo changing $FN chmod 0750 "$FN" done
It’s simple enough—it echoes the filename that it is working on,
then it changes that file’s permissions. What if you want it to work
quietly sometimes, not echoing the filename? How would we add an option
to turn off this verbose behavior while preserving the for
loop?
#!/usr/bin/env bash # cookbook filename: use_up_option # # use and consume an option # # parse the optional argument VERBOSE=0; if [[ $1 = -v ]] then VERBOSE=1; shift; fi # # the real work is here # for FN in "$@" do if (( VERBOSE == 1 )) then echo changing $FN fi chmod 0750 "$FN" done
We add a flag variable, $VERBOSE
, to
tell us whether or not to echo the filename as we work. But once the
shell script has seen the -v
and set the
flag, we don’t want the -v
in the
argument list any more. The shift statement tells
bash to shift its arguments down one position,
getting rid of the first argument ($1
) as $2
becomes $1
, and $3
becomes $2
, and so on.
That way, when the for
loop
runs, the list of parameters (in $@) no longer contains the -v
but starts with the next parameter.
This approach of parsing arguments is alright for handling a
single option. But if you want more than one option, you need a bit more
logic. By convention, options to a shell script (usually) are not
dependent on position; e.g., myscript -a
-p
should be the same as myscript -p
-a
. Moreover, a robust script should be able to handle
repeated options and either ignore them or report an error. For more
robust parsing, see the recipe on bash’s getopts
built-in (Parsing Arguments for Your Shell Script).
18.225.117.233