Functions: Parameters
Naming your parameters
Convention goes a long way; like “a destination is always first and source is the second argument”. But you can improve readability quite a lot, by immediately assigning the positional parameters to local variables.
copy_file_if_present()
{
local dst="$1"
local src="$2"
if [ -f "${src}" ]
then
cp "${dst}" "${src}"
fi
}
I would like to write more about this, since its very much key to readable shell scripts. But it’s just as easy as that.
Passing more than 9 arguments
Parameter of a shell function are accessed like $1
, $2
.. $9
. But the
caller can pass more arguments. To extract them, you shift
used-up parameters
away. Then what used to be in $2
is now in $1
and so forth. $#
holds the
number of parameters still available to the function:
foo()
{
while [ $# -ne 0 ]
do
printf "%s\n" "$1"
shift
done
}
foo 1 2 3 4 5 6 7 8 9 10
1
2
3
4
5
6
7
8
9
10
Combined with shift
you can write a function to have more than nine named
parameters:
foo()
{
local a1="$1"; shift
local a2="$1"; shift
local a3="$1"; shift
local a4="$1"; shift
local a5="$1"; shift
local a6="$1"; shift
local a7="$1"; shift
local a8="$1"; shift
local a9="$1"; shift
local a10="$1"; shift
printf "%s\n" "${a1}"
printf "%s\n" "${a2}"
printf "%s\n" "${a3}"
printf "%s\n" "${a4}"
printf "%s\n" "${a5}"
printf "%s\n" "${a6}"
printf "%s\n" "${a7}"
printf "%s\n" "${a8}"
printf "%s\n" "${a9}"
printf "%s\n" "${a10}"
}
Note
In the hated dash, you can not shift, if there are no parameters left. So you need to test for a parameters presence explicitly.
local x="$1"; [ $# -ne 0 ] && shift
Often its nicer and probably faster as well, to do a multiple shift instead.
local a1="$1"
local a2="$2"
local a3="$3"
local a4="$4"
local a5="$5"
local a6="$6"
local a7="$7"
local a8="$8"
local a9="$9"
shift 9
local a10="$1"; shift
...
Forwarding parameters
When you write a wrapper function, you often only need to consider some
of the parameters and can pass the rest of the parameters “as is”. Here "$@"
comes in handy, which is a shortcut for “all remaining parameters”.
foo()
{
local cc="$1" ; shift
case "${cc}" in
'gcc')
gcc-10 "$@"
;;
'clang')
clang-11 "$@"
;;
esac
}
Note
Do not confuse
"$@"
with$*
, which means all remaining parameters as a string. The string would then be reparsed by the shell, which may lead to quoting misery.