I want to create a function which iterates through an array and inserts the given value, if its not yet included. I am using this function on two different parts of my code and so I have to use different arrays. Therefore I am delivering the array names to the function. Now I can't figure out how to allocate a slot of the array to store the element at this place.
Here is my code:
name=("hello" "world")
function f {
array_name=$2[@]
array=("${!array_name}")
length=${#array_name[@]}
for (( i = 0; i <= $length; i++ )); do
if [[ "${array[i]}" = "$1" ]];
break;
fi
if [[ "$i" = "$length" ]]; then
${2[$length+1]=$1};
fi
done
}
f "test" "name"
Edit: I want the array to append the given value so something like this
for i in ${name[@]}
do
echo $i
done
would have this output:
hello
world
test
but apparently "${2[$length+1]=$1}"
is not working.
(Idea for passing the array is from here: bash how to pass array as an argument to a function)
To pass an entire array to a function, only the name of the array is passed as an argument. result = calculateSum(num); However, notice the use of [] in the function definition. This informs the compiler that you are passing a one-dimensional array to the function.
Answer: An array can be passed to a function by value by declaring in the called function the array name with square brackets ( [ and ] ) attached to the end. When calling the function, simply pass the address of the array (that is, the array's name) to the called function.
3.4 Passing dynamic arrays to functionsDynamic arrays can also be passed to functions in the same way as static arrays.
In case of an array (variable), while passed as a function argument, it decays to the pointer to the first element of the array. The pointer is then passed-by-value, as usual.
To pass multidimensional arrays to a function, only the name of the array is passed to the function (similar to one-dimensional arrays). Note: In C programming, you can pass arrays to functions, however, you cannot return arrays from functions.
How arrays are passed to functions in C/C++. In C, when we pass an array to a function say fun(), it is always treated as a pointer by fun(). Below example demonstrates the same. unsigned int n = sizeof(arr)/sizeof(arr[0]); printf("nArray size inside fun() is %d", n); int arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
If you don't take any particular actions, an array will be passed by value, with a complete copy of the array. And in the earliest languages, like Fortran or Algol, each language often had its own very particular ways of passing arrays, although in general, they followed the same rules as other types.
To pass multidimensional arrays to a function, only the name of the array is passed to the function (similar to one-dimensional arrays). Notice the parameter int num [2] [2] in the function prototype and function definition:
If I understand correctly you want to append a value to an array if this value is not yet in the array, but the tricky part is that the array name is passed to the function.
One possibility is to see the problem from a different viewpoint: you can pass to the function the value to be inserted and the full array, and the function will set a global variable that you will recover after its execution. For our test example we'll use:
array=( hello world "how are you today?" )
and we'll try to insert test
and hello
(so that hello
will not be inserted):
f() {
# This function will set the global variable _f_out to an array obtained from
# the positional parameters starting from position 2, with $1 appended if and
# only if $1 doesn't appear in the subsequent positional parameters
local v=$1 i
shift
_f_out=( "$@" )
for i; do [[ $i = $v ]] && return; done
_f_out+=( "$v" )
}
Let's use it:
$ array=( hello world "how are you today?" )
$ f test "${array[@]}"
$ array=( "${_f_out[@]}" )
$ printf '%s\n' "${array[@]}"
hello
world
how are you today?
test
$ f hello "${array[@]}"
$ array=( "${_f_out[@]}" )
$ printf '%s\n' "${array[@]}"
hello
world
how are you today?
test
It works.
Remark. I used for i; do
. It's a nice shortcut for for i in "$@"; do
.
You really want to fiddle with simili-pointers and do the appending in place (this is not really in the spirit of Bash—that's why it's a bit clumsy). The tool for that is to use printf
with the -v
option: from help printf
:
-v var assign the output to shell variable VAR rather than display it on the standard output
The good thing is that it also works with array fields.
Warning: you might see other methods that use eval
. Avoid them like the plague!
f() {
local array_name=$2[@] i
local array=( "${!array_name}" )
for i in "${array[@]}"; do [[ $i = $1 ]] && return; done
# $1 was not found in array, so let's append it
printf -v "$2[${#array[@]}]" '%s' "$1"
}
and let's try it:
$ array=( hello world "how are you today?" )
$ f test array
$ printf '%s\n' "${array[@]}"
hello
world
how are you today?
test
$ f hello array
$ printf '%s\n' "${array[@]}"
hello
world
how are you today?
test
It works too.
Note. With both methods you can very easily have a return
code of the function, e.g., 0
(success) if the value was inserted, and 1
(failure) if the value was already there (or the other way round)—the adaptation is straightforward and left as an exercise. This might be useful in Method 1 to determine whether you need to update array
to the returned value _f_out
or not. In that case, you could even slightly modify f
so that it doesn't even set _f_out
when the value is already in the array.
Caveat. In both methods shown I assumed that your arrays have contiguous indices that start at 0 (i.e., non-sparse arrays). I think it's a safe assumption here; but if it is not the case, these methods are broken: the first one will (after reassignment) transform the array into a non-sparse one, and the second one might overwrite fields (as, for an array a
, ${#a[@]}
expands to the number of elements in the array, not the highest index + 1 found in the array).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With