Hello,
Please tell me if there is a better way to get the number of elements from an array that is passed to a function.
This is what works on Solaris 8 (ksh) but it looks odd:
loop_array() {
array_name=$2
b1='\${\#'
b2='[@]}'
nr_elements=`eval echo $b1$array_name$b2`
# this one prints the actual variable I want to reassign ...
echo $nr_elements
# it seems to only work like this
nr_elements=`eval echo $nr_elements`
echo $nr_elements
# this line prints out the number of elements correctly but when I assign it to a variable with ` ` I get bad substitution error
eval echo \${\#$array_name[@]}
#...
}
Thanks
I guess the 'last' acctualy is the 'nr_elements' or you have something missed.
If it is, let see what the 'last' has:
You have build correct string "\${\#$array_name[@]}"; asked to 'eval'uate it - have in result "${#<arr_name>[@]}"; and asking to execute it!
Try execute this line with correct array name: you will have :command not found!
Because it will produce a number of the array elements and a number is not a command by itself.
I did not clear understand what do you need: the correct number of element for any given array or the command itself into a variable?
If the array element number, you do not need to escape the characters in b1 and b2 (acctualy, I do not see why do you need them) :
b1='${#';
b2='[@]}'
eval echo $b1$array_name$b2
I do not see any reason to build a command itself and after that execute it. It will required double execution, as you already figured it out.
So, you have an array name in a variable and would like to call a function that returns the aray elements number? A function need to be executed to get a result. So:
>elms(){ eval echo \${\#$1[@]\}; return 0;}
># - checking:
>a1=(aa dd cc rr);
>a2=(klkl ioio opo);
> echo `elms a1`
4
> echo $(elms a2)
3
To get just a "echo $nr_elements" the nr_elements should be a variable, which you could set in a function. So
>set_elms_n(){ elm_n=$(eval echo \${\#$1[@]\}); return 0;}
>set_elms_n a1
>echo $elm_n;
4
>set_elms_n a2
>echo $elm_n;
3
That what you was looking for?
This is partially what I wanted, thank you for the tips.
What I need is to use the variable inside the function itself not outside.
For example:
set_elms_n(){ elm_n=$(eval echo \${\#$1[@]\}); echo $elem_n; return 0;}
# when I run "set_elms_n a1" I get no result.
The rest of the function continues with a loop through the array backwards(decrementing the number of lines variable), so that is why I need the variable to be set inside the function.
- you just misspell variable in function!
> set_elms_n(){ elm_n=$(eval echo \${\#$1[@]\}); echo $elm_n; return 0;}
> set_elms_n a1
4
try this as well:
# pass arrays by value not by "reference"
trn_arr()
{
set -A arr $1
echo "array length= ${#arr[*]}"
pos=$2
pos=$(( pos -1 ))
echo " $2 element of array = ${arr[pos]}"
}
set -A myarr 9 8 7 6 5 4 3 2 1
trn_arr "${myarr[*]}" 4
It is oversimlified.
Also the array is redefined (acctually, it is where the problem set):
> a11=("1-two words" 2-jkjk 3-uiuiu 4-opopop 5-tytyty)
> ec ${#a11[@]}
5
> trn_arr "${a11[*]}" 2
array length= 6
2 element of array = words
>
Just recall this last pointed by Jim try to send an array by value, instead of by reference (in shell - just the name.)
The point is that it could be done in correct way, but with appropriate call syntaxis:
>
> arr=("two words" "one" "more")
>
> prt_arr(){
> n_el=$#; # number of positional parameters could be the same as in arr
> # the positional parameters are array, acctualy;
> # no needs to re-assign
> # could be accesed with simplified way: $1, $2, .. that is
> # the same, as ${arr[0]}, ${arr[1]}, ...
> while [[ ! -z $* ]];
> do /usr/bin/echo "$1\n";
> shift;
> done;
> echo "orig number : $n_el";}
>
> # now it is important to call in correct way: with @ and in ""
> prt_arr "${arr[@]}"
two words
one
more
orig number : 3
>
> # other way call does not produce expected result:
> prt_arr ${arr[@]}
two
words
one
more
orig number : 4
> prt_arr ${arr[*]}
two
words
one
more
orig number : 4
> prt_arr "${arr[*]}"
two words one more
orig number : 1
>