Libre Software to randomly pick name from text file

11 replies [Last post]
g3tr00tacc3ss
Offline
Joined: 11/03/2021

Hello Everyone,

I have a home library of books, and I am on the hunt for a Libre program to randomly select a book to read from a list in a text file. All I could could find is a freeware proprietary program, which is not someone I am willing to use (especially for such a small task). Does anyone have any suggestions? I asked this question on Reddit, and all that was recommended was a website that would do the picking (running non-free software, no doubt). I am sure that I could cobble together a bash script that could do the task, but I would much rather have a GUI.

Thanks!

Magic Banana

I am a member!

Offline
Joined: 07/24/2010

Assuming one line per book in a file named "file", you can execute that in the terminal:
$ shuf -n 1 file
Of course, the file can be named more meaningfully and you can change the number to pick more than one book (their output order is pseudorandom too).

I am sure that I could cobble together a bash script that could do the task, but I would much rather have a GUI.

You can have a GUI with Shell script, thanks to Zenity. You can read that heavily-commented Shell script for inspiration (fewer than 50 lines, but it does more than picking a line in a single file): https://dcc.ufmg.br/~lcerf/en/utilities.html#trivialibre

g3tr00tacc3ss
Offline
Joined: 11/03/2021

Thank you! I had no knowledge of Zenity's existence.

Lef
Lef
Offline
Joined: 11/20/2021

Here is a trivial zenity script:

randombook.sh
--------------
#!/bin/sh
if zenity --title="A Random Book" --question --text="$(shuf -n 1 textfile.txt)\n, would you like another?"; then
bash randombook.sh
else
echo "Bye"
fi
--------------

This script is so trivial I doubt it's copyrightable but if it is, it's licensed to the world under CC0.

You don't need to call randombook.sh from a terminal window, you can open it with from a shortcut icon as if it was a program.

If you have more specific requests for what you want the program to do, we can probably craft it for you.

g3tr00tacc3ss
Offline
Joined: 11/03/2021

This is awesome! Thanks. I wonder if it would be possible to have the script remove the line from the text file after it's been picked (so it's not picking books I've already read in the future)?

Magic Banana

I am a member!

Offline
Joined: 07/24/2010

Sure. The following script exemplifies the use of different Zenity's dialog options: file selection if no argument is given, error if the file is not readable, and question if the file is readable. In the latter case, the script picks a random line number, shows the related line, asks the user if she accepts to read it. If so, the line is removed. Otherwise, the script picks another line number (nothing prevents the new line from being the same, actually), until the user accepts.

#!/bin/sh
file="$1"
if [ -z "$file" ]
then
file=$(zenity --file-selection --title='Select a file with one book per line')
[ -z "$file" ] && exit 1
fi
if [ ! -r "$file" ]
then
zenity --error --title='Random Book' --text="\"$file\" is not readable!"
exit 66
fi
while :
do
line=$(expr $(od -A n -N 2 /dev/urandom) % $(wc -l < "$file") + 1)
zenity --question --title='Random Book' --text="I picked $(sed -n ${line}p "$file").\n\nWill you read it? If not, I will keep that book for another time and pick another one." && break
done
sed -i ${line}d "$file"

g3tr00tacc3ss
Offline
Joined: 11/03/2021

This is fantastic! Thank you!

Magic Banana

I am a member!

Offline
Joined: 07/24/2010

With a new loop to add books (through the entry dialog) and the possibility to not pick a book (hence a normal exit without any book removed):
#!/bin/sh
file="$1"
if [ -z "$file" ]
then
file=$(zenity --file-selection --title='Select a file with one book per line')
[ -z "$file" ] && exit 1
fi
if [ ! -r "$file" -o ! -w "$file" ]
then
zenity --error --title='Random Book' --text="\"$file\" is not readable or writable!"
exit 66
fi
while :
do
book=$(zenity --entry --title='Random Book' --text='Enter new book (or not):')
[ -z "$book" ] && break
printf "$book
"
done >> "$file"
while :
do
zenity --question --title='Random Book' --text='Do you want to pick a book?' || exit
line=$(expr $(od -A n -N 2 /dev/urandom) % $(wc -l < "$file") + 1)
zenity --question --title='Random Book' --text="I picked $(sed -n ${line}p "$file").\n\nWill you read it? If so, I will remove it from the list." && break
done
sed -i ${line}d "$file"

g3tr00tacc3ss
Offline
Joined: 11/03/2021

Thanks again. What line would I have to change in order to have it default to my home directory rather than recent?

Magic Banana

I am a member!

Offline
Joined: 07/24/2010

There does not seem to exist an option for that: https://help.gnome.org/users/zenity/stable/file-selection.html

However, have you understood you can call the script (including in a launcher) with the file in argument? Doing so, the file selection dialog does not appear.

g3tr00tacc3ss
Offline
Joined: 11/03/2021

I think I was able to find the solution from this site: https://ostechnix.com/zenity-create-gui-dialog-boxes-in-bash-scripts/

I simply added --filename "/home/${USER}/" so it looks like:

file=$(zenity --file-selection --filename "/home/${USER}/" --title='Select a file with one book per line')

Thanks again for all your help. This is really handy!

Magic Banana

I am a member!

Offline
Joined: 07/24/2010

It was actually the first option in https://help.gnome.org/users/zenity/stable/file-selection.html

I somehow skipped it when I skimmed the page.

I simply added --filename "/home/${USER}/"

You can more simply write:
--filename ~/