Reputation: 2418
I am trying to write a simple function in bash which takes 2 arguments, a string and an array.
At the very beggining of the function I check for the number of arguments
function is2args() {
if [ $# -le 1 ]; then
return 1
fi
return 0
}
I then attempt the following
arr=()
is2args "" "${arr[@]}" # returns 1
This triggers the if statement as bash for some reason thinks there is only one argument however if the list is an empty string it works
arr=()
is2args "" "" # returns 0
or filled with elements
arr=(
"element"
)
is2args "" "${arr[@]}" # returns 0
and default to an empty string
arr=()
is2args "" "${arr[@]:-""}" # returns 0
I don't quite understand what is going on. It is my understanding this is the correct way to pass a list however it seems that an empty list is ignored for whatever reason.
Should I really be setting a default empty string every time I send through an array or is there a way to catch this in the function itself?
Upvotes: 1
Views: 2445
Reputation: 246867
You might want to pass the name of the array (note that the below requires bash 4.3):
myfunc() {
local arg1=$1
local -n array=$2
printf "first arg: %q\n" "$arg1"
echo array:
declare -p array
}
arr=()
myfunc "foo" arr
Upvotes: 3
Reputation: 295500
If you want to pass a fixed argument and an array, shift
the first element off; what remains in "$@"
is the contents of your array. If the array is empty, $@
will be empty too. (If $#
is 0 after the shift
, that means your array's length was 0 -- or no array was passed; the two cases are precisely identical).
myfn() {
local string_arg=$1; shift || { echo "ERROR: Initial argument missing" <&2; return 1; }
local -a array_args=( "$@" )
echo "Initial argument is: $string_arg"
echo "Array has length ${#array_args[@]}"
echo "Array elements:"
printf ' - %q\n' "${array_args[@]}"
}
array=( "first array member" "second array member" )
myfn "first argument" "${array[@]}"
Upvotes: 2
Reputation: 246867
This is expected. The "${arr[@]}"
form expands to put each element of the array on the command line, and there are no elements in the array.
The "${arr[*]}"
form will expand to one string consisting of the elements concatenated with a space (by default).
You might try this to test the arguments passed:
$ nargs () {
local i=0
for arg do printf "%d\t>%s<\n" $((++i)) "$arg"; done
}
$ nargs foo "${arr[@]}"
1 >foo<
$ nargs foo "${arr[*]}"
1 >foo<
2 ><
$ arr=(1 2 3)
$ nargs foo "${arr[@]}"
1 >foo<
2 >1<
3 >2<
4 >3<
$ nargs foo "${arr[*]}"
1 >foo<
2 >1 2 3<
$ IFS=,
$ nargs foo "${arr[*]}"
1 >foo<
2 >1,2,3<
Upvotes: 3