Append elements to an array in bash - arrays

I tried the += operator to append an array in bash but do not know why it did not work
#!/bin/bash
i=0
args=()
while [ $i -lt 5 ]; do
args+=("${i}")
echo "${args}"
let i=i+1
done
expected results
0
0 1
0 1 2
0 1 2 3
0 1 2 3 4
actual results
0
0
0
0
0

It did work, but you're only echoing the first element of the array. Use this instead:
echo "${args[#]}"
Bash's syntax for arrays is confusing. Use ${args[#]} to get all the elements of the array. Using ${args} is equivalent to ${args[0]}, which gets the first element (at index 0).
See ShellCheck: Expanding an array without an index only gives the first element.
Also btw you can simplify let i=i+1 to ((i++)), but it's even simpler to use a C-style for loop. And also you don't need to define args before adding to it.
So:
#!/bin/bash
for ((i=0; i<5; ++i)); do
args+=($i)
echo "${args[#]}"
done

Related

why it does not start from the first line of array?

code:
#!/bin/bash
aa=(1 2 3 4)
for i in "${aa[#]}";do
echo "${aa[$i]}"
done
exit 0
it will prints out:
2
3
4
i dont think theres an error in my code, I already double checked it with shellcheck too.
The loop iterates over the array's values, not its indices. It'll be clearer if you make the array values strings:
aa=(foo bar baz quux)
for entry in "${aa[#]}";do
echo "$entry"
done
Notice how I got rid of the aa[$i] lookup and just print the variable directly. This prints:
foo
bar
baz
quux
If you want to iterate over the indices add !:
for i in "${!aa[#]}";do
echo "${aa[$i]}"
done
Or use a C-style loop:
for ((i = 0; i < "${#aa[#]}"; i++)); do
echo "${aa[$i]}"
done

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:)

How to append values to an array in Bash by adding one element to the previous entry?

I have a list of numbers 1 2 3 4 5 that I am trying to organize into an array where the values are in a sequence where the current value is the summation of the previous values in the array (like this): 1 3 6 10 15. My current code is as follows:
array=()
for n in `seq 1 5`
do
if [ $n -eq 1 ]; then
array+=($n)
else
value=$n
index="$(($n-1))"
array+=(`echo ${array[$index]}+$value`)
fi
done
However, when I try checking the array echo "${array[#]}" I get 1 +2 +3 +4 +5. How can I best go about solving this problem?
It is quite simple if you know how to get the last element of the array in bash arrays!. You can just use a negative index ${myarray[-1]} to get the last element. You can do the same thing for the second-last, and so on; in Bash:
fbseries=()
for ((i=1; i<=5; i++)); do
if [ "$i" -eq 1 ]; then
fbseries+=("$i")
else
fbseries+=( $(( ${fbseries[-1]} + $i )) )
fi
done
With the example and some modifications all you need is as above.
You are pretty close the a working code. Here I also added some improvements:
array=()
for n in {1..5}
do
if [ "$n" -eq 1 ]; then
array+=("$n")
else
value="$n"
index="$((n-1))"
array+=($((${array[$index]}+value)))
fi
done
You can avoid using seq, and you don't need an echo but a calculus.
BTW, that's not a Fibonacci serie.

giving an array sum values in a for loop

Im having this annoying problem which not even my teacher can solve:/.
I want to fill an array with sum values from 1 to 100 this is my code:
while [ $i -le 100 ]
do
#filling the list with the sums of i at the pos i
sumList[$i]=$(echo $i | sum)
echo $i |sum
echo $sumList[$i]
i=$(($i+1))
done
And for some reason it just fills all spots with the first value (00034 1)
I have no Idea what to do
Here's ShellCheck:
Line 6:
echo $sumList[$i]
^-- SC1087: Use braces when expanding arrays, e.g. ${array[idx]} (or ${var}[.. to quiet).
^-- SC2128: Expanding an array without an index only gives the first element.
And with this fixed:
i=1
while [ $i -le 100 ]
do
#filling the list with the sums of i at the pos i
sumList[$i]=$(echo $i | sum)
echo $i |sum
echo ${sumList[$i]}
i=$(($i+1))
done
You get all the different checksums and block counts that you'd expect:
32802 1
32802 1
00035 1
00035 1
32803 1
32803 1
00036 1
00036 1
32804 1
32804 1
[...]
If you actually examine the output from that script (removing the echo $i |sum line), it should become evident what's happening:
00034 1[0]
00034 1[1]
00034 1[2]
: : :
00034 1[100]
As you can see, the line echo $sumList[$i] is giving you $sumList (which is identical to ${sumList[0]})and $i separately and that's because, as per the bash documentation (my emphasis):
Any element of an array may be referenced using ${name[subscript]}. The braces are required to avoid conflicts ...
So, if you change that to the correct ${sumList[$i]}`, you'll see that you are indeed setting up the array correctly, you just weren't printing it correctly:
00034 1
32802 1
00035 1
: : :
08244 1
And, for what it's worth, there are other facilities in bash that will make your code more succinct, if that is your goal:
for i in {0..100}; do sumList[$i]="$(echo $i | sum)" ; done
IFS=$'\n' ; echo "${sumList[*]}"

bash fill an array of integers from arguments and sort it

I looked everybody but I'm stuck with this code.
For example :
The user calls ./array.sh 3 5 6 2 1
I am supposed to sort (i thought bubble sort) and print the array sorted.
#! /bin/bash
tab=( $# )
define -i temp
for ((i = ${#tab[*]-1 ; i >= 0 ; i--)) ; do
for ((j = 0 ; i - 1; j++)) ; do
if [ ${tab[$i]} > ${tab[$i+1]} ] then
$temp = ${tab[$i+1]
${tab[$i+1]} = ${tab[$i]}
${$tab[$i]} = $temp
fi
done
echo ${tab[*]} #print the array
But bash is not happy with that, he keeps tellin me that I cannot assing values like that.
What do I do wrong ? Can you help me please ? I looked in a lot of places but there is no way to find the solution.
Thanks you in advance guys.
You cannot assign a value to a value (e.g. ${tab[$i+1]} = ${tab[$i]}); you must assign to a name or to an array element. Also, you may not have space on either side of the equals sign (=) in a bash assignment, except in numeric context.
And you dropped some closing braces.
And you misspelled "declare".
And you need a semicolon or newline between your if condition and your then.
And you didn't terminate your inner loop.
And you reference a non-existent array element via ${tab[$i+1]}.
And your inner loop has a constant as its termination condition.
And ${#tab[*]-1} incorrectly attempts to do math inside the braces delimiting the variable reference.
And you referenced the wrong index variable (consistently) in your inner loop.
And > is a redirection operator, not greater than, except in numeric context.
Once you clear up that multitude of errors, you end up with
#! /bin/bash
tab=( $# )
declare -i temp
for ((i = ${#tab[*]} - 1; i > 0 ; i--)) ; do
for ((j = 0 ; $j < $i; j++)) ; do
if [ ${tab[$j]} -gt ${tab[$j+1]} ]; then
temp=${tab[$j+1]}
tab[$j+1]=${tab[$j]}
tab[$j]=$temp
fi
done
done
echo ${tab[*]} #print the array
which actually works.
Your variable assignment syntax is all wrong.
First, you don't put $ before the variable being assigned.
Second, you must not have spaces around =.
So it should be:
temp=${tab[$i+1]}
tab[$i+1]=${tab[$i]}
tab[$i]=$temp
I understand that you are working on a class assignment or such and are restricted in how you are allowed to solve the problem. For those not so restricted, here is a simple solution using standard unix tools:
#!/bin/bash
( IFS=$'\n'; echo "$*" ) | sort -n
Sample usage:
$ script.sh 3 5 6 2 1
1
2
3
5
6
Explanation:
( IFS=$'\n'; echo "$*" )
This causes the command line arguments to be printed, one per line. This is in a subshell so that the assignment to IFS does not affect the rest of the script.
sort -n
-n tells sort to apply a numeric sort.

Resources