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.

When I execute the following code, the output of the printf statement appears to show array out of sequence. In the declare statement the Source item is declared before Destination and in the output it's reversed.

YELLOW=$'\e[93m'
declare -A OP=( [Description]="remote to destination" [Source]="/var/www" [Destination]="/foo/bar" [Log]="my.log" [Email]="me@here" );

NO_COLS=`tput cols`
COLS_PER_COL=$(($NO_COLS/3))
PRINT_FORMAT="%"$COLS_PER_COL"s%""s\n"

for i in "${!OP[@]}"; do
    printf $PRINT_FORMAT "$i :" " $YELLOW${OP[$i]}$ENDCOL"
done ;

Output looks like

         Description : remote to destination
         Destination : /foo/bar
              Source : /var/www
                 Log : my.log
               Email : me@here

Can anyone tell me what is happening here? or how I can achieve the proper order according to the array declaration?

share|improve this question
2  
Associative arrays have no inherent order. The insertion order is not preserved. –  glenn jackman Jan 28 at 3:58
    
That makes sense, although it appears to obey some type of order because it consistently prints the same sequence even if you move the variables around in the declaration. It just so happened that I declared them similar to the output which is why I thought there was something wrong with the code. Problem solved with the answer here... just curious. –  user1074170 Jan 28 at 14:05

1 Answer 1

up vote 6 down vote accepted

Associative array in bash (and in other languages) does not preserve the order of elements in declaration.

You can add another associative array to keep track the order of declaration:

YELLOW=$'\e[93m'
declare -A OP=( [Description]="remote to destination"
                [Source]="/var/www"
                [Destination]="/foo/bar"
                [Log]="my.log"
                [Email]="me@here" )

declare -A IP=( [1]="Description"
                [2]="Source"
                [3]="Destination"
                [4]="Log"
                [5]="Email" );

NO_COLS="$(tput cols)"
COLS_PER_COL="$((NO_COLS/3))"
PRINT_FORMAT="%${COLS_PER_COL}s%s\n"

for i in "${!IP[@]}"; do
  k=${IP[$i]}
  printf "$PRINT_FORMAT" "$k :" " $YELLOW${OP[$k]}$ENDCOL"
done
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.