Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash: Split two strings directly into associative array

I have two strings of same number of substrings divided by a delimiter.

I need to create key-value pairs from substrings.

Short example: Input:

firstString='00011010:00011101:00100001'
secondString='H:K:O'
delimiter=':'

Desired result:

${translateMap['00011010']} -> 'H'
${translateMap['00011101']} -> 'K'
${translateMap['00100001']} -> 'O'

So, I wrote:

IFS="$delimiter" read -ra fromArray <<< "$firstString"
IFS="$delimiter" read -ra toArray <<< "$secondString"
declare -A translateMap

curIndex=0
for from in "${fromArray[@]}"; do
    translateMap["$from"]="${toArray[curIndex]}"
    ((curIndex++))
done

Is there any way to create the associative array directly from 2 strings without the unneeded arrays and loop? Something like:

IFS="$delimiter" read -rA translateMap["$(read -ra <<< "$firstString")"] <<< "$secondString"

Is it possible?

like image 762
anotherCryptoFun Avatar asked Nov 23 '25 02:11

anotherCryptoFun


1 Answers

A (somewhat convoluted) variation on @accdias's answer of assigning the values via the declare -A command, but will need a bit of explanation for each step ...

First we need to break the 2 variables into separate lines for each item:

$ echo "${firstString}" | tr "${delimiter}" '\n'
00011010
00011101
00100001

$ echo "${secondString}" | tr "${delimiter}" '\n'
H
K
O

What's nice about this is that we can now process these 2 sets of key/value pairs as separate files.

NOTE: For the rest off this discussion I'm going to replace "${delimiter}" with ':' to make this a tad bit (but not much) less convoluted.

Next we make use of the paste command to merge our 2 'files' into a single file; we'll also designate ']' as the delimiter between key/value mappings:

$ paste -d ']' <(echo "${firstString}" | tr ':' '\n') <(echo "${secondString}" | tr ':' '\n')
00011010]H
00011101]K
00100001]O

We'll now run these results through a couple sed patterns to build our array assignments:

$ paste -d ']' <(echo "${firstString}" | tr ':' '\n') <(echo "${secondString}" | tr ':' '\n') | sed 's/^/[/g;s/]/]=/g'
[00011010]=H
[00011101]=K
[00100001]=O

What we'd like to do now is use this output in the typeset -A command but unfortunately we need to build the entire command and then eval it:

$ evalstring="typeset -A kv=( "$(paste -d ']' <(echo "${firstString}" | tr ':' '\n') <(echo "${secondString}" | tr ':' '\n') | sed 's/^/[/g;s/]/]=/g')" )"

$ echo "$evalstring"
typeset -A kv=( [00011010]=H
[00011101]=K
[00100001]=O )

If we want to remove the carriage returns and put on a single line we append another tr at the output from the sed command:

$ evalstring="typeset -A kv=( "$(paste -d ']' <(echo "${firstString}" | tr ':' '\n') <(echo "${secondString}" | tr ':' '\n') | sed 's/^/[/g;s/]/]=/g' | tr '\n' ' ')" )"

$ cat "${evalstring}"
typeset -A kv=( [00011010]=H [00011101]=K [00100001]=O )

At this point we can eval our auto-generated typeset -A command:

$ eval "${evalstring}"

And now loop through our array displaying the key/value pairs:

$ for i in ${!kv[@]}; do echo "kv[${i}] = ${kv[${i}]}"; done
kv[00011010] = H
kv[00100001] = O
kv[00011101] = K

Hey, I did say this would be a bit convoluted! :-)

like image 177
markp-fuso Avatar answered Nov 24 '25 16:11

markp-fuso



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!