Emissions Tracker

Updated algorithm for my paper picker bash script

Paper Picker Update

Published: Sat, 16 Aug 2025 08:15:28-4:00
Bash | Hyprland

Several months ago after switching to Hyrland, I started using their wallpaper utility, Hyprpaper. I have multiple monitors and like to spice my life up by cycling through wallpapers once an hour or so. I created some bash scripts and a cron job to run the scripts on a timely basis, and choose which directory to pull the images from using wofi. While it worked, it had several problems associated with it. I had to hard code the monitor names into the script, and when I switched between computers it was a nuisance to have to update this. The algorithm to get random non-duplicated wallpapers was also not very good. I had used a while loop to continuously call a function until the names didn’t match. The logic to add a third monitor was also buggy, and it was difficult to get it to deal with situations where there were fewer wallpapers in the directory than monitors. But it sort of worked! so for several months I left it alone.

Recently I got a new monitor and added a third monitor, and I decided to fix the script. I didn’t want to run into these problems again when changing my monitor configuration.

Getting the Monitors

One of the issues with the old script was that the monitor names were hard coded. Any time I changed computers or monitors it would break, and I had to update the script to work with my new setup. I couldn’t just stick it in version control and forget about it.

# Use hyprctl to get a list of monitors and store them in an array.
readarray -t monitors < <(hyprctl monitors | awk '$1 == "Monitor" { print $2 }')
num_monitors=${#monitors[@]}

This uses awk to parse the output of the hyprctl utility that lists information about the monitors connected to your system in a format that is trivially read by awk. The < <( ) is used for process substitution. This creates a virtual file of the output from awk and passes that to readarray, which expects a file instead of a string. This creates an array from the output of awk. finally, ${#monitors[@]} gets the length of the newly created array and stores it as a variable for later use.

New Random Wallpaper Logic

I also updated the logic to get a random wallpaper. As I said in the previous post, it is possible to use something like shuf -n num_monitors to get a list of random wallpaper, but I would still need to handle cases where there weren’t enough wallpapers per the number of monitors, and I thought it would be more fun to create the logic myself (Hint: it was).

# Get a random paper, add it to the array of papers to be used, and
# remove it from the array of possible papers to choose from only if
# there is at least one remaining in the array.
function get_random_paper() {
  # Get a random index from from the length of the papers array.
  local random=$((RANDOM % ${#papers[@]}))
  local paper=${papers[random]}
  #This initializes an empry array to appened to below
  local temp_array=()

# Create a temporary array of all remaining wallpapers except for the one
# that was just choosen This will remove it from the array so it will not
# be duplicated later.
  for p in "${papers[@]}"; do
    if [ "$paper" != "$p" ]; then
      temp_array+=("$p")
    fi
  done

# If temp_array is length 0, then all papers have been removed.
# If so, it should not be removed from the array of avaialable
# wallpapers. This wallpaper will then be duplicated on all remaining
# monitors. If more wallpapers remain, set the papers array to newly
# created array.
  if [ "${#temp_array[@]}" -gt 0 ]; then
    papers=("${temp_array[@]}")
  fi

  # Add the selected wallpaper to the array of papers to be used.
  papers_array+=("$paper")
}

# Run the random wallpaper function once per avaialable monitor
for ((i = 0; i < num_monitors; i++)); do
  get_random_paper
done

Additional Small Fixes

I made some additional small fixes. I was changing directory in the script to run commands, but I updated it be directory agnostic by setting the location of the required files as a variable at beginning of the script. The only thing that should need to change about the script is updating this if the hypr config files are not located in the default location. Additionally, I used find with readarray to create the array of the absolute file paths to the wallpaper files.

I also ran ShellCheck, which recommended splitting the export of the hyprlctl instance into two lines, one to get the instance, one to export it, and pointed out some spots where I had forgotten to quote variables.

System Crafters Web Ring

Messing around with computers and coding since I was 8. Now getting paid to do what I love.