Shell Script - Find length of an array passed as parameter to a function - arrays

I am trying to access my array passed as parameter to my function inside my shell script. I am able to process individual element of the array but when I try to find length of the array, it only shows 1. My script is:
ar=(8 2 3 4 5 6 7)
test() {
sum=0
ref=$1[#]
echo ${#ref[#]}
for i in ${!ref}
do
sum=`expr $sum + $i`
done
echo "sum is: $sum"
}
test ar
If I do
echo ${#ref}
it gives me 5 as result. Dont know the reason for this result as well.
Is there any way I can find a way out of this ?

ts () {
set $1[*]
ref=(${!1})
echo ${#ref[*]}
for i in ${ref[*]}
do
(( sm += i ))
done
echo sum is: $sm
}
ar=(8 2 3 4 5 6 7)
ts ar
Output
7
sum is: 35

Related

Populate array in a for loop

I have an array of strings to pass through a script. The script is well-behaved, and will return error code 0 if the string "passes" and non-zero if it "fails." If the string passes, it should be included in a final array to be output or written to file or etc.
The problem I'm having is that the only item ending up in my final array is the first "passing" string.
#!/bin/bash
# validator.sh
if [[ $1 -le 10 ]]; then
exit 0
else
exit 1
fi
#!/bin/bash
# main.sh
numbers=(2 4 6 8 10 12 14 16)
keep=()
for n in ${numbers[#]}; do
if ./validator.sh $n; then
keep+=("$n")
fi
done
echo $keep
Running main.sh produces:
$ ./main.sh
2
but I expect 2 4 6 8 10
Unless you meant keep to be an array of matching elements, change:
keep+=("$n")
to
keep="$keep $n"
That would work with any Bourne compatible shell and is therefore better, if you're looking for BASH specific solution, the below will also work:
keep+="${n} "
If you DO want it to be an array, then in order to output all elements, you can use:
echo ${keep[#]}
As noted by #Jetchisel and #kamilCuk in the comments.
Since you wrote you want to output all elements or save them to a file, I had assumed you don't actually need an array here but perhaps you plan to use this data in other ways later:)

tcsh array variable substitution

I'm attempting to modify a script that works for a different application. i could start over, but I'd like to learn how to do this. Here are some arrays I'm manually setting instead of using user input or an input file:
set mbeg= (1 2 3 4)
set mmid= (5 6 7 8)
set mend= (9 0 0 0)
what I really want to do is loop through $time and $case and have it return the array value for the loop variables.
foreach time (beg mid end)
foreach case (1 2 3 4)
echo \${m$time}[$case]
For this example, I want it to return:
1 2 3 4 5 6 7 8 9 0 0 0 0
I can get as far as getting echo \${m$time} to return "mbeg" but i can't figure out how to get the array counter in there. Is this something simple that can be done, or should I change the strategy? Other strategies include brute force input of the array name and if/else statements to choose only the array corresponding to the $time variable.
foreach time (beg mid end)
foreach j ( 1 2 3 4 )
if ($time == beg) then
echo $mbeg[$j]
elseif ( $time == mid ) then
echo $mmid[$j]
else
echo $mend[$j]
I could also attempt to read from an input file. To date, I have done this using grep and sed to reduce the file to a single variable.
Thanks.

bash function returns with changed indexes

I have following code:
#!/bin/bash
function getSlots {
declare -A slots
for index in `seq 7 10`;
do
slots[$index]=$index
done
echo ${slots[#]}
}
slots=($(getSlots))
for i in ${!slots[#]};
do
echo "$i ${slots[$i]}"
done
When I run, my output is this:
0 10
1 7
2 8
3 9
Why do indexes change when I call the function?
arr=(...) re-indexes the array.
With your current approach, you cannot preserve the indexes as any information about them is lost as soon as you leave the function (you just echo the values).
You can use nameref (requires bash 4.3 or later) to modify the supplied array directly and since you are using only numbers as indexes, regular array will suffice:
#!/usr/bin/env bash
function get_slots {
local index # makes index local
local -n _arr=$1 # _arr points to the supplied array
_arr=() # empties the array
for index in {7..10}; do
_arr[index]=$index # assigns new values to the array
done
}
get_slots slots
for i in "${!slots[#]}"; do
echo "$i ${slots[$i]}"
done
Because the echo ${slots[#]} at the end of the function getSlots expands to echo 10 7 8 9 and that output is what you are assigning to the array slots by doing:
slots=($(getSlots))
Another interesting question would be why echo ${slots[#]} expands to echo 10 7 8 9 and not to echo 7 8 9 10.
That is because the slots inside getSlots is declared as an associative array, not an array, i.e.:
declare -A slots
Replace the line above with:
declare -a slots
and you will get the following output:
0 7
1 8
2 9
3 10

Bash Array - Cant get input from a loop in to my array correctly

I run this script as
script.sh 'abcdefghijk123456789!##$%^&' 'aaaa4444ged###'
it should be able to produce an array containing something like
1 1 1 1 15 15 15 15 7 5 23 23 23
with 12 indexes 0 - 11, but what i get is
1 1 1 1 1 5 1 5 1 5 1 5 7 5 2 3 2 3 2 3
with 20 indexes.
I want to populate a array with base numbers for a given char.
So i have a list of chars that we will be using in $startstring ie.
abcc5678% we can say that every char in $startstring is = to one char in the
$charset ie. abcd5678!%. This code finds what each $startstring char is equal
to $charset's index number. That information is what i am trying to capture in a
array. Mostly it works except a bug where instead of the whole number 10 getting
stored in decoded[1] what happens is the number 10 is split in to 1 and 0 and
then both are put in under separate indexes. So instead of a "1 10 1" and 3
indexes i end up with 4 indexes with "1 1 0 1". Im sure im just handling my
variables the wrong way but i searched and searched and now my brain is gonna
explode so i came here for some relief. or hope of it anyway. Can someone tell
me the proper way to insert digits in to this decoded[] array?
#!/bin/bash
#declare -i decoded
charset=$1
startstring=$2
start=$((${#charset}-1))
echo "Setting up CharMap to CharSet"
for i in $(eval echo {0..$start})
do
echo $i " = " ${charset:$i:1}
done
echo "Proving Chars Were Mapped Correctly."
start2=$((${#startstring}))
start3=$((${#charset}-1))
for i in $(eval echo {0..$start2})
do
for p in $(eval echo {0..$start3})
do
if [ "${startstring:$i:1}" == "${charset:$p:1}" ]
then
echo "found that" ${startstring:$i:1}"=" $p 'from the charmap.'
decoded+=$p #<--### I DONT THINK THIS IS WHAT I NEED ###
fi
done
done
##################Just trying to print my new array#########################
start4=$((${#decoded}-1))
echo 'Testing the array $decoded'
echo 'the var start4(length of $decoded) = '$start4
echo 'this number should equal ----------> '$start2
echo 'Printing out the $decoded array in a for loop'
for c in $(eval echo {0..$start4})
do
echo ${decoded[$c]} ###DOESNT WORK LIKE I THOUGHT# also tried echo ${decode:$c:1}
done
decoded+=$p appends $p as a string, not as an array entry. Essentially, you're creating the string "11111515151575232323" by appending all the index numbers together. (Actually, I get "00001414141464322222227" from your example, because of index bound problems. I'll let you worry about that...)
To store the decoded values as an array, set decoded to an empty array before the loop, and then use decoded+=("$p") to add $p as an element:
decoded=() # create an empty array
for i in $(eval echo {0..$start2})
do
for p in $(eval echo {0..$start3})
do
if [ "${startstring:$i:1}" == "${charset:$p:1}" ]
then
echo ${startstring:$i:1} "=" $p
decoded+=("$p") # append $p as a new array element
fi
done
done
Then, to get the size of the array (rather than a string length), use ${#decoded[#]}:
start4=$((${#decoded[#]}-1))

How to find the length of an array in shell?

How do I find the length of an array in shell?
For example:
arr=(1 2 3 4 5)
And I want to get its length, which is 5 in this case.
$ a=(1 2 3 4)
$ echo ${#a[#]}
4
From Bash manual:
${#parameter}
The length in characters of the expanded value of parameter is substituted. If parameter is ‘’ or ‘#’, the value substituted is the
number of positional parameters. If parameter is an array name
subscripted by ‘’ or ‘#’, the value substituted is the number of
elements in the array. If parameter is an indexed array name
subscripted by a negative number, that number is interpreted as
relative to one greater than the maximum index of parameter, so
negative indices count back from the end of the array, and an index of
-1 references the last element.
Length of strings, arrays, and associative arrays
string="0123456789" # create a string of 10 characters
array=(0 1 2 3 4 5 6 7 8 9) # create an indexed array of 10 elements
declare -A hash
hash=([one]=1 [two]=2 [three]=3) # create an associative array of 3 elements
echo "string length is: ${#string}" # length of string
echo "array length is: ${#array[#]}" # length of array using # as the index
echo "array length is: ${#array[*]}" # length of array using * as the index
echo "hash length is: ${#hash[#]}" # length of array using # as the index
echo "hash length is: ${#hash[*]}" # length of array using * as the index
output:
string length is: 10
array length is: 10
array length is: 10
hash length is: 3
hash length is: 3
Dealing with $#, the argument array:
set arg1 arg2 "arg 3"
args_copy=("$#")
echo "number of args is: $#"
echo "number of args is: ${##}"
echo "args_copy length is: ${#args_copy[#]}"
output:
number of args is: 3
number of args is: 3
args_copy length is: 3
Assuming bash:
~> declare -a foo
~> foo[0]="foo"
~> foo[1]="bar"
~> foo[2]="baz"
~> echo ${#foo[*]}
3
So, ${#ARRAY[*]} expands to the length of the array ARRAY.
in tcsh or csh:
~> set a = ( 1 2 3 4 5 )
~> echo $#a
5
In the Fish Shell the length of an array can be found with:
$ set a 1 2 3 4
$ count $a
4
This works well for me:
arglen=$#
argparam=$*
if [ $arglen -eq '3' ];
then
echo Valid Number of arguments
echo "Arguments are $*"
else
echo only four arguments are allowed
fi
For those who still searching a way to put the length of an array into a variable:
foo="${#ARRAY[*]}"

Resources