Why is $# always 0 in my function?
Solution 1
You're calling the main
function with no argument. So $#
in the main function is always 0.
Each function instance has its own arguments. (“Instance” means that if the function is started multiple times (through recursive calls), each call has its own arguments.) The positional parameters $1
, $2
, etc., as well as the associated parameters $#
, $*
and $@
refer to the arguments passed in the function call. For example, if you call main foo bar
then inside the main
function the value of $1
will be foo
, the value of $#
will be 2 and so on.
If you want to pass the arguments of the script to a function, use "$@"
. This construct expands to the list of arguments passed to the script (or to the function, if called inside a function). Note that unlike what normally happens with double quotes, the parameters are passed separately, "$@"
is a list of strings and not a single string. The double quotes are necessary, otherwise the parameters are not passed as is but treated as a whitespace-separated list of file name patterns.
function main {
if (( $# < 1 )); then
usage
fi
echo "good"
}
main "$@"
Solution 2
This should work:
#!/bin/bash
set -x
NARGS=$#
function main {
if [ $NARGS -lt 1 ]; then
usage
fi
echo good
}
function usage {
echo "Usage: $0 <outputdir>"
exit 1
}
main
I left the set -x
there on purpose. It's useful to debug these errors. If you don't pass any arguments to the main
function, $#
becomes 0 inside it (replace $NARGS
with $#
in the if
condition to see this).
Related videos on Youtube
devios1
Updated on September 18, 2022Comments
-
devios1 over 1 year
Bash is driving me nuts. I can't figure out why the following (nor any of the dozens of variations I've literally copied and pasted from examples) fails to work:
#!/bin/bash echo $# function main { if (( $# < 1 )); then usage fi echo "good" } function usage { echo "Usage: $0 <outputdir>" exit 1 } main
For some reason the argument check fails every time, even when I pass an argument and can clearly see
$#
is set as expected.-
G-Man Says 'Reinstate Monica' over 5 yearsSee also: What does
$#
mean in shell?
-
-
devios1 almost 11 yearsI see! So calling a function clobbers (some of?) the argument variables. Good to know! (Obviously very new to bash, sorry)
-
Dophlin almost 11 yearsI didn't know either, thus the usefulness of
set -x
:) -
Franco Ferrari almost 11 years@chaiguy Only
$1
,$2
, etc get clobbered, as they get re-used for the function arguments.main $NARGS
is pointless as the argument isn't being used.$NARGS
becomes$1
inside the function. -
Dophlin almost 11 years@DavidBaggerman, Thanks. Edited to correct and avoid confusion.
-
Stéphane Chazelas almost 11 yearsAs an extra note, the
function foo {
syntax is theksh
function definition syntax (as opposed to the Bourne/POSIXf() {
one) and inksh
, with that syntax,$0
is also overridden inside the function.$0
is overridden whatever the syntax inzsh
(unless insh
emulation) and is never overridden in other shells likeash
,yash
orbash
. -
Sungguk Lim about 10 yearsthis is probably right answer.