TransWikia.com

How do I iterate through multiple bash arrays and elements that are not previously stored as variables?

Unix & Linux Asked by jamescranston on December 15, 2021

Problem I’m trying to Solve

The problem I am trying to solve is being able to iterate through elements in two bash arrays as well as individual elements such that these elements are not stored previously as variables; they are declared on the spot:

for e in "$(seq -f "number-%g" 0 4) $(seq -f "number-%g" 5 9) number-10" ; do echo $e; done

When I execute this, I see:

$ for e in "$(seq -f "number-%g" 0 4) $(seq -f "number-%g" 5 9) number-10" ; do echo $e; done
number-0 number-1 number-2 number-3 number-4 number-5 number-6 number-7 number-8 number-9 number-10

it seems as is everything is printing out on the same line.

Resources I’ve consulted

I’ve read and experimented with resources on these pages:

Experiments I’ve tried

Experiment 1

This stores the arrays in intermediate variables:

seq1="$(seq -f "number-%g" 0 4)"
seq2="$(seq -f "number-%g" 5 9)"
elem="number-10"
all=("${seq1[@]}" "${seq2[@]}" "${elem}")

Printing this out yields:

$ for e in $all; do echo $e; done
number-0
number-1
number-2
number-3
number-4

which seems to not pick up the second array or the last element.

Experiment 2

Here I explicitly store two arrays instead of generating them with seq, however, I 1.) do not want to store intermediate variables for this question as per "problem I am trying to solve", and 2.) I want to use the seq command as opposed to stating the arrays explicitly.

$ seq1=("number-0" "number-1" "number-2" "number-3" "number-4")
$ seq2=("number-5" "number-6" "number-7" "number-8" "number-9")
$ all=("${seq1[@]}" "${seq2[@]}" "number-10")

Printing this out along with "number-10" yields:

$ for e in "${all[@]}"; do echo $e; done
number-0
number-1
number-2
number-3
number-4
number-5
number-6
number-7
number-8
number-9
number-10

I look forward to hearing some bash tricks! Thanks!

One Answer

So, let's talk about this:

$ seq1="$(seq -f "number-%g" 0 4)"
$ seq2="$(seq -f "number-%g" 5 9)"
$ elem="number-10"
$ all=("${seq1[@]}" "${seq2[@]}" "${elem}")
$ declare -p all
declare -a all=([0]=$'number-0nnumber-1nnumber-2nnumber-3nnumber-4' [1]=$'number-5nnumber-6nnumber-7nnumber-8nnumber-9' [2]="number-10")
$ for e in $all; do echo $e; done
number-0
number-1
number-2
number-3
number-4

Note declare -p -- that's very handy to inspect the contents of variables.

all is an array variable. When you dereference this as $all, you are effectively doing ${all[0]} -- i.e. only retrieving the first element.

See that the all array only has 3 elements? The seq1 and seq2 variables are not arrays, they are plain "scalar" variables. Similarly to the previous paragraph, you can use array element syntax to refer to scalar variables:

$ x="hello world"
$ declare -p x
declare -- x="hello world"
$ echo "$x"
hello world
$ echo "${x[0]}"
hello world
$ echo "${x[1]}"

$ echo "${x[*]}"
hello world
$ echo "${x[@]}"
hello world

If you want to execute an external command and capture the lines of output, use the mapfile command. You also need to use a process substitution to invoke the external command.

$ unset seq1 seq2 all
$ mapfile -t seq1 < <(seq -f "number-%g" 0 4)
$ mapfile -t seq2 < <(seq -f "number-%g" 5 9)
$ all=("${seq1[@]}" "${seq2[@]}" "${elem}")
$ declare -p all
declare -a all=([0]="number-0" [1]="number-1" [2]="number-2" [3]="number-3" [4]="number-4" [5]="number-5" [6]="number-6" [7]="number-7" [8]="number-8" [9]="number-9" [10]="number-10")
$ printf "%sn" "${all[@]}"
number-0
number-1
number-2
number-3
number-4
number-5
number-6
number-7
number-8
number-9
number-10

To generate this sequence in bash without using any external tools, use Brace Expansion:

$ all=( "number-"{0..10} )
$ declare -p all
declare -a all=([0]="number-0" [1]="number-1" [2]="number-2" [3]="number-3" [4]="number-4" [5]="number-5" [6]="number-6" [7]="number-7" [8]="number-8" [9]="number-9" [10]="number-10")

Answered by glenn jackman on December 15, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP