LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-13-2020, 10:01 AM   #1
GPGAgent
Senior Member
 
Registered: Oct 2018
Location: Surrey UK
Distribution: Mint 20 xfce 64bit
Posts: 1,026
Blog Entries: 3

Rep: Reputation: 133Reputation: 133
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.
 
Old 04-13-2020, 10:06 AM   #2
dugan
LQ Guru
 
Registered: Nov 2003
Location: Canada
Distribution: distro hopper
Posts: 11,246

Rep: Reputation: 5323Reputation: 5323Reputation: 5323Reputation: 5323Reputation: 5323Reputation: 5323Reputation: 5323Reputation: 5323Reputation: 5323Reputation: 5323Reputation: 5323
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.

Last edited by dugan; 04-13-2020 at 10:16 AM.
 
1 members found this post helpful.
Old 04-13-2020, 10:33 AM   #3
michaelk
Moderator
 
Registered: Aug 2002
Posts: 25,764

Rep: Reputation: 5931Reputation: 5931Reputation: 5931Reputation: 5931Reputation: 5931Reputation: 5931Reputation: 5931Reputation: 5931Reputation: 5931Reputation: 5931Reputation: 5931
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

Last edited by michaelk; 04-13-2020 at 10:34 AM.
 
Old 04-13-2020, 12:38 PM   #4
GPGAgent
Senior Member
 
Registered: Oct 2018
Location: Surrey UK
Distribution: Mint 20 xfce 64bit
Posts: 1,026

Original Poster
Blog Entries: 3

Rep: Reputation: 133Reputation: 133
Quote:
Originally Posted by michaelk View Post
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
 
Old 04-13-2020, 12:40 PM   #5
GPGAgent
Senior Member
 
Registered: Oct 2018
Location: Surrey UK
Distribution: Mint 20 xfce 64bit
Posts: 1,026

Original Poster
Blog Entries: 3

Rep: Reputation: 133Reputation: 133
Quote:
Originally Posted by dugan View Post
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
 
Old 04-13-2020, 01:08 PM   #6
michaelk
Moderator
 
Registered: Aug 2002
Posts: 25,764

Rep: Reputation: 5931Reputation: 5931Reputation: 5931Reputation: 5931Reputation: 5931Reputation: 5931Reputation: 5931Reputation: 5931Reputation: 5931Reputation: 5931Reputation: 5931
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.
 
Old 04-13-2020, 01:17 PM   #7
shruggy
Senior Member
 
Registered: Mar 2020
Posts: 3,677

Rep: Reputation: Disabled
+1 to michaelk. Replace the while loop with one mapfile command.
 
2 members found this post helpful.
Old 04-13-2020, 01:25 PM   #8
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,992

Rep: Reputation: 7337Reputation: 7337Reputation: 7337Reputation: 7337Reputation: 7337Reputation: 7337Reputation: 7337Reputation: 7337Reputation: 7337Reputation: 7337Reputation: 7337
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)
 
Old 04-14-2020, 05:49 AM   #9
GPGAgent
Senior Member
 
Registered: Oct 2018
Location: Surrey UK
Distribution: Mint 20 xfce 64bit
Posts: 1,026

Original Poster
Blog Entries: 3

Rep: Reputation: 133Reputation: 133
Thumbs up

Quote:
Originally Posted by shruggy View Post
+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
 
Old 04-14-2020, 05:54 AM   #10
GPGAgent
Senior Member
 
Registered: Oct 2018
Location: Surrey UK
Distribution: Mint 20 xfce 64bit
Posts: 1,026

Original Poster
Blog Entries: 3

Rep: Reputation: 133Reputation: 133
Thumbs up

Quote:
Originally Posted by pan64 View Post
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.
 
Old 04-14-2020, 06:07 AM   #11
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,992

Rep: Reputation: 7337Reputation: 7337Reputation: 7337Reputation: 7337Reputation: 7337Reputation: 7337Reputation: 7337Reputation: 7337Reputation: 7337Reputation: 7337Reputation: 7337
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.
 
1 members found this post helpful.
  


Reply

Tags
bash script



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] Can I set the cups output order to always print in reverse order Thane Ubuntu 3 07-09-2018 09:49 PM
Logi Sales Manager on Ncurses (invoice, invoicing, orders, order, sale order, sales order...)? Xeratul Linux - Software 0 03-25-2017 02:45 PM
Running mysql from ssh & query statement has a Text Header in the SELECT statement? djlerman Linux - Server 6 11-19-2013 06:33 PM
Question on how linux determines drive "names" bpalmer Linux - Hardware 4 03-01-2005 05:56 AM
How do I write a make install Makefile that determines if user is root? SheldonPlankton Programming 3 08-13-2004 05:39 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 09:39 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration