1

I have two bash arrays, and I want to append array strings to the end of the name array elements.

array=(a b c)
name=(toto_ tata_)

result :

toto_a
toto_b
toto_c
tata_a
tata_b
tata_c

I tried those command :

for i in "${name[@]}"
do
    arra=( "${i/%/$array[@]}" )
done
printf '%s\n' "${arra[@]}"

3 Answers 3

2

Using Brace Expansion to expand as a cross-product

readarray -t new_array < <(IFS=,; eval "printf '%s\n' {${name[*]}}{${array[*]}}")
# ....................................................^..........^^...........^

then

$ declare -p new_array
declare -a new_array=([0]="toto_a" [1]="toto_b" [2]="toto_c" [3]="tata_a" [4]="tata_b" [5]="tata_c")

Eval is necessary to allow the variable expansion to occur first, then perform the brace expansion second.

Sign up to request clarification or add additional context in comments.

3 Comments

Or just: (IFS=,; eval "printf '%s\n' {${name[*]}}{${array[*]}}")... Nice, but not easy to debug! I don't like to play with $IFS... but here, it's fun ;-)
Or even, moving eval at begin of line: . <(IFS=,;echo $'printf "%s\\n"' "{${name[*]}}{${array[*]}}")
Nice but this will fail to work properly if an array element contains a ,. Also it must be noted that array elements will be subject to eval too (Assume name=(toto_ tata_ '$(some_command)'), then some_command will be executed by eval!). So array elements must be sanitized if they come from an external source.
1

I'd recommend using a second for:

array=(a b c)
name=(toto_ tata_)
arra=()

for i in "${name[@]}"; do
    for j in "${array[@]}"; do
        arra+=("$i$j")
    done
done
printf '%s\n' "${arra[@]}"

Will produce:

toto_a
toto_b
toto_c
tata_a
tata_b
tata_c

Try it online!

1 Comment

This could by done without for loop!
1

Second for could be avoided by Parameter expansion

for nam in "${name[@]}";do printf "${nam/%/%s\\n}" "${array[@]}";done

will produce:

toto_a
toto_b
toto_c
tata_a
tata_b
tata_c

For fun, some variants (without any for loop):

printf -v fmt "${name[*]/%/%%s\\n}"
printf "${fmt// }" ${array[@]}
toto_a
tata_b
toto_c
tata_

or

printf -v fmt "${name[*]/%/%%s\\n}";printf "${fmt// }" ${array[@]}{,}
toto_a
tata_b
toto_c
tata_a
toto_b
tata_c

then without for, but with a fork to sort

printf -v fmt "${name[*]/%/%%s\\n}";printf "${fmt// }" ${array[@]}{,} |
    sort -k 1r,1.5
toto_a
toto_b
toto_c
tata_a
tata_b
tata_c

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.