LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   What determines the output order from a select statement (https://www.linuxquestions.org/questions/programming-9/what-determines-the-output-order-from-a-select-statement-4175673131/)

GPGAgent 04-13-2020 10:01 AM

What determines the output order from a select statement
 
What determines the order a - select opt in "${!ListOfNames[@]}" Quit - statement outputs?

The script ReadTXTFile.sh

Code:

#!/bin/bash

declare -A ListOfNames

filename="$HOME/bin/DATA/TVNames.txt"
n=1
while read line; do
# reading each line
    ListOfNames[$line]=$n
n=$((n+1))
done < $filename

COLUMNS=20
PS3="Please enter your choice: "
select opt in "${!ListOfNames[@]}" Quit
do
                [[ "$REPLY" =~ [^0-9] ]] && (( REPLY = $# + 1 ))

                if (( REPLY <= ${#ListOfNames[*]} + 1 ))
                then
                        break
                else
                                echo "ERROR: Invalid choice.  Must choose one of the numbers provided."
                fi
done

if [[ "$opt" == Quit ]]
then
        echo "quitting"
else
    echo "$opt"
#
#        cat <<-OUT
#                =====================================
#                Name of TV person is: $opt
#                Prompt for filename, title, artist etc
#                =====================================
#                Now this will continue with the processing
#                part of the script.......
#                ====== Finished Okay ================
#        OUT

The above code reads this list from a file:
Code:

charlie@charlie-machine:~/bin/DATA$ ls
TVNames.txt
charlie@charlie-machine:~/bin/DATA$ cat TVNames.txt
Carol Kirkwood - BBC Weather Girl     
Nina Warhurst - BBC News Girl   
Lorraine Kelley - ITV       
Victoria Graham - BBC Spotlight   
Kirstie Allsopp - Property Expert
Catherine Southon - Antiques Expert
Nicki Chapman - Wanted Down Under   
Holly Willoughby - ITV
IMAGES-
charlie@charlie-machine:~/bin/DATA$ ReadTXTFile.sh
 1) Holly Willoughby - ITV
 2) Catherine Southon - Antiques Expert
 3) IMAGES-
 4) Victoria Graham - BBC Spotlight
 5) Carol Kirkwood - BBC Weather Girl
 6) Kirstie Allsopp - Property Expert
 7) Nicki Chapman - Wanted Down Under
 8) Nina Warhurst - BBC News Girl
 9) Lorraine Kelley - ITV
10) Quit
Please enter your choice:

But outputs in a different order.

dugan 04-13-2020 10:06 AM

It's undefined.

You're reading the list into a hash table (well, an "associative array", which is almost certainly implemented using a hash table), and then just printing out the hash table as-is. Hash tables have undefined ordering.

michaelk 04-13-2020 10:33 AM

I agree that you should not use an associative array. There are several ways to create an array from a file.

bash 4
readarray -t ListOfNames < "$filename"

read -r -a ListOfNames <<< "$(filename)"

declare -A ListOfNames
read -r line; do
ListOfNames+=("$line")
done < "$filename"

Change your select line to
select opt in "${ListOfNames[@]}" Quit

GPGAgent 04-13-2020 12:38 PM

Quote:

Originally Posted by michaelk (Post 6111090)
I agree that you should not use an associative array. There are several ways to create an array from a file.

bash 4
readarray -t ListOfNames < "$filename"

read -r -a ListOfNames <<< "$(filename)"

declare -A ListOfNames
read -r line; do
ListOfNames+=("$line")
done < "$filename"

Change your select line to
select opt in "${ListOfNames[@]}" Quit

Changed the select line as you suggested results in this:

Code:

charlie@charlie-machine:~$ ReadTXTFile.sh
1) 8          7) 9
2) 6          8) 7
3) 10          9) 2
4) 4          10) 3
5) 1          11) Quit
6) 5
Please enter your choice: 11
quitting
charlie@charlie-machine:~$

and the script:
Code:

#!/bin/bash

declare -A ListOfNames

filename="$HOME/bin/DATA/TVNames.txt"
n=1
while read line; do
# reading each line
    ListOfNames[$line]=$n
n=$((n+1))
done < $filename

COLUMNS=20
PS3="Please enter your choice: "
select opt in "${ListOfNames[@]}" Quit            ### <================================================
do
                [[ "$REPLY" =~ [^0-9] ]] && (( REPLY = $# + 1 ))

                if (( REPLY <= ${#ListOfNames[*]} + 1 ))
                then
                        break
                else
                                echo "ERROR: Invalid choice.  Must choose one of the numbers provided."
                fi
done

if [[ "$opt" == Quit ]]
then
        echo "quitting"
else
    echo "$opt"

Thanks anyway

GPGAgent 04-13-2020 12:40 PM

Quote:

Originally Posted by dugan (Post 6111082)
It's undefined.

You're reading the list into a hash table (well, an "associative array", which is almost certainly implemented using a hash table), and then just printing out the hash table as-is. Hash tables have undefined ordering.

Ahhh, I never thought (knew) that - I'll look into it.

Cheers

michaelk 04-13-2020 01:08 PM

I guess I wasn't precise enough in my post. Switch to loading a standard array as suggested in my post and also change the select line.

shruggy 04-13-2020 01:17 PM

+1 to michaelk. Replace the while loop with one mapfile command.

pan64 04-13-2020 01:25 PM

I don't understand why do we need associative array at all. As a minimal modification (I would do something like):
Code:

#!/bin/bash

declare -a ListOfNames  # if I remember well

filename="$HOME/bin/DATA/TVNames.txt"
while read -r line; do
# reading each line
    ListOfNames+=( "$line" )
done < $filename

COLUMNS=20
PS3="Please enter your choice: "
select opt in "${ListOfNames[@]}" Quit            ### <================================================
do
                [[ "$REPLY" =~ [^0-9] ]] && (( REPLY = $# + 1 ))

                if (( REPLY <= ${#ListOfNames[*]} + 1 ))
                then
                        break
                else
                                echo "ERROR: Invalid choice.  Must choose one of the numbers provided."
                fi
done

if [[ "$opt" == Quit ]]
then
        echo "quitting"
else
    echo "$opt"
fi

(not tested)

GPGAgent 04-14-2020 05:49 AM

Quote:

Originally Posted by shruggy (Post 6111149)
+1 to michaelk. Replace the while loop with one mapfile command.

Brilliant - I didn't know the builtin command existed:
Code:

charlie@charlie-machine:~$ mapfile -t < bin/DATA/TVNames.txt
charlie@charlie-machine:~$ printf "%s\n" "${MAPFILE[@]}"
Carol Kirkwood - BBC Weather Girl     
Nina Warhurst - BBC News Girl   
Lorraine Kelley - ITV       
Victoria Graham - BBC Spotlight   
Kirstie Allsopp - Property Expert
Catherine Southon - Antiques Expert
Nicki Chapman - Wanted Down Under   
Holly Willoughby - ITV
Susanna Reid - ITV
Neighbours - CH5 2020
Kate Garraway - ITV 2020
X
charlie@charlie-machine:~$ cat bin/DATA/TVNames.txt
Carol Kirkwood - BBC Weather Girl     
Nina Warhurst - BBC News Girl   
Lorraine Kelley - ITV       
Victoria Graham - BBC Spotlight   
Kirstie Allsopp - Property Expert
Catherine Southon - Antiques Expert
Nicki Chapman - Wanted Down Under   
Holly Willoughby - ITV
Susanna Reid - ITV
Neighbours - CH5 2020
Kate Garraway - ITV 2020
X

thanks

GPGAgent 04-14-2020 05:54 AM

Quote:

Originally Posted by pan64 (Post 6111152)
I don't understand why do we need associative array at all. As a minimal modification (I would do something like):
Code:

#!/bin/bash

declare -a ListOfNames  # if I remember well

filename="$HOME/bin/DATA/TVNames.txt"
while read -r line; do
# reading each line
    ListOfNames+=( "$line" )
done < $filename

COLUMNS=20
PS3="Please enter your choice: "
select opt in "${ListOfNames[@]}" Quit            ### <================================================
do
                [[ "$REPLY" =~ [^0-9] ]] && (( REPLY = $# + 1 ))

                if (( REPLY <= ${#ListOfNames[*]} + 1 ))
                then
                        break
                else
                                echo "ERROR: Invalid choice.  Must choose one of the numbers provided."
                fi
done

if [[ "$opt" == Quit ]]
then
        echo "quitting"
else
    echo "$opt"
fi

(not tested)

I don't need an associative array, it was the first bit of code I found that did what I wanted, almost, and I was trying to figure out what it was doing, your post worked just fine and I understand the differences now, ans updated my notes - many thanks much appreciated.

pan64 04-14-2020 06:07 AM

Ok, great.
If you think your question is answered please mark the thread solved.
Also if you wish to say thanks just click on yes.


All times are GMT -5. The time now is 03:58 AM.