Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.
#!/bin/bash
arr=(a b c d)
declare -A brr
for i in ${!arr[@]}
do
  brr[${arr[$i]}]=$i
done
echo ${brr[@]}                             #0 1 2 3

Is there any way to reverse the values and key pairs using sed or any other command. I think I would have to just do some pattern change of text instead of using bash loops, perhaps something like.

brr=($(echo ${!arr[@]} | sed commands))

so that the new array becomes like brr=([a]=0 [b]=1 [c]=2 [d]=3) if I use brace expansion it can come up to this point:

#!/bin/bash
arr=(a b c d)
declare -A brr
var=${arr[@]}
var=${var// /,}
brr=$(eval echo [{$var}]=)
echo $brr                              #[a]= [b]= [c]= [d]=

now I just need to add the keys 0,1,2,3

EDIT : I was able to do it but can I make it shorter and simpler especially the sed lines

#!/bin/bash
arr=(a b c d)
declare -A Rev
var=${arr[@]}                    #var is equal to a b c d
var=${var// /,}                  #var is equal to a,b,c,d after adding , for space
brr=$(eval echo Rev[{$var}]=)    #brr equal to Rev[a]= Rev[b]= Rev[c]= Rev[d]=

#NOW I NEED TO CHANGE 
#Rev[a]= Rev[b]= Rev[c]= Rev[d]=
#to
#Rev['a']=0;Rev['b']=1;Rev['c']=2;Rev['d']=3

r="$(echo $brr | 
sed 's/ /\n/g' | sed '/./=' | sed '/./N; s/\n//' | 
  sed 's/\(^[0-9]\{1,\}\)\(.*\)/\2$(echo \1 - 1 | bc)/' | tr '\n' ';' |
                                                          sed "s/\[/\[\'/g;s/\]/\'\]/g")"
#pipe the output of echo(Rev[a]= Rev[b]= Rev[c]= Rev[d]=) to sed
#convert space to newlines
#add line numbers
#put the line numbers adjacent to the values Rev[a],Rev[b],Rev[c],Rev[d] like
# 1rev[a]=
# 2Rev[b]=
# 3Rev[c]=
# 4Rev[d]=
#change 1Rev[a]= format to Rev[a]=1
#convert newlines to ; looking like Rev[a]=0;Rev[b]=1;Rev[c]=2;Rev[d]=3
#put quotes around the keys Rev['a']=0;Rev['b']=1;Rev['c']=2;Rev['d']=3

eval $r
echo ${Rev[@]}      #0 1 2 3
echo ${!Rev[@]}     #a b c d
share|improve this question
3  
Don't use sed for this, you'll end up with a parsing corner case nightmare. –  Chris Down Oct 6 '13 at 6:34

3 Answers 3

up vote 4 down vote accepted

I would heed @ChrisDown's advice and not try to do something clever here. I would create the for loop and reverse the keys with the values in the new array. It's only a few lines of code.

Anything you create in this manner is going to be more difficult for others to support down the road, and more difficult for you to remember/understand how it works when you revisit the code in the future.

share|improve this answer
1  
Never mind that the shell expansion to generate the input to sed is using a bash loop internally anyway, so whatever reason you have for avoiding iterating over the array is lost, with the additional loss of having to fork() a new process for the sed on top of that. –  dannysauer Oct 6 '13 at 19:20
#!/bin/bash
arr=(a b c d)
set -- $(echo ${arr[@]} | tr ' ' '\n' | sed "s/.*/arr['&']=/")
eval echo $(seq 1 ${#arr[@]} | sed 's/\(.*\)/${\1}$(echo \1 -1 | bc)/') 

or

#!/bin/bash
declare -A brr
arr=(a b c d)
eval "brr=($(eval echo $(sed 's/\([0-9]\)/[${arr[\1]}]=\1/g' <(echo ${!arr[@]}))))"
echo ${brr[@]}

Output:

#arr['a']=0 arr['b']=1 arr['c']=2 arr['d']=3
share|improve this answer

As others have said, I think sed would be a difficult solution.

The following loop could accomplish what you want:

arr=(a b c d)
for i in ${!arr[@]}; do
    brr+=("[${arr[$i]}]=$i")
done
echo ${brr[@]}
#[a]=0 [b]=1 [c]=2 [d]=3
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.