Hello everyone,

Hoping that this is a good place to post a question about Bash scripting. My wife and I have run into a problem in PhotoPrism where it keeps tagging pictures and videos with similar names together and so the thumbnail and the video do not match. I decided that rather than try to get her iPhone to tweak its naming it’s easier to just offload to a directory then rename every file to a UUID before sending to photoprism. I’m trying to write a bash script to simplify this but cannot get the internal loop to fire. The issue appears to be with the ‘while IFS= read -r -d ‘’ file; do’ portion. Is anyone able to spot what the issue may be?

#! /bin/bash
echo "This script will rename all files in this directory with unique names. Continue? (Y/N)"
read proceed
if [[ "$proceed" == "Y" ]]; then
	echo "Proceed"
	#use uuidgen -r to generate a random UUID.
	#Currently appears to be skipping the loop entirely. the find command works so issue should be after the pipe.
	   
# Troubleshooting
#Seems like changing IFS to $IFS helped. Now however it's also pulling others., don't think this is correct.
#verified that the find statement is correct, its the parsing afterwards that's wrong.
#tried removing the $'\0' after -d as that is string null in c. went to bash friendly '' based on https://stackoverflow.com/questions/57497365/what-does-the-bash-read-d-do
#issue definitely appears to be with the while statement
	find ./ -type f \( -iname \*.jpg -o -iname \*.png \) | while IFS= read -r -d '' file; do
	   echo "in loop"
	   echo "$file"
	   #useful post https://itsfoss.gitlab.io/post/how-to-find-and-rename-files-in-linux/
	   #extract the directory and filename
	   dir=$(dirname "$file")
	   base=$(basename "$file")
	   echo "'$dir'/'$base'"
	   #use UUID's to get around photoprism poor handling of matching file names and apples high collision rate
	   new_name="$dir/$(uuidgen -r)"
	   echo "Renaming ${file} to ${new_name}"
	   #mv "$file" "$new_name" #uncomment to actually perform the rename.
	done
	echo "After loop"
else
	echo "Cancelling"
fi

    • atzanteol@sh.itjust.works
      link
      fedilink
      English
      arrow-up
      2
      ·
      edit-2
      3 hours ago

      I’m totally in favor of people asking other people for help with these things. But here’s what Claude gave.

      Found the Issue!

      The problem is a mismatch between your find output and what read expects:

      • find with a regular pipe outputs newline-separated filenames
      • read -r -d '' expects null-terminated input (the -d '' means “use null byte as delimiter”)

      Solution 1: Use -print0 with find (Recommended)

      Change your find command to use -print0:

      find ./ -type f \( -iname "*.jpg" -o -iname "*.png" \) -print0 | while IFS= read -r -d '' file; do
      

      Solution 2: Remove -d '' from read

      find ./ -type f \( -iname "*.jpg" -o -iname "*.png" \) | while IFS= read -r file; do
      

      Additional Issues to Fix:

      1. Quote your wildcards: -iname \*.jpg should be -iname "*.jpg" to prevent shell expansion
      2. File extension preservation: Your script generates UUIDs but loses the file extension (.jpg, .png). You probably want to keep those!

      Improved Script:

      #! /bin/bash
      echo "This script will rename all files in this directory with unique names. Continue? (Y/N)"
      read proceed
      if [[ "$proceed" == "Y" ]]; then
          echo "Proceed"
          
          find ./ -type f \( -iname "*.jpg" -o -iname "*.png" \) -print0 | while IFS= read -r -d '' file; do
              echo "in loop"
              echo "$file"
              
              # Extract the directory and extension
              dir=$(dirname "$file")
              ext="${file##*.}"  # Get file extension
              
              # Generate new name with UUID but keep extension
              new_name="$dir/$(uuidgen -r).$ext"
              
              echo "Renaming ${file} to ${new_name}"
              # mv "$file" "$new_name"  # Uncomment to actually perform the rename
          done
          echo "After loop"
      else
          echo "Cancelling"
      fi
      

      The key changes:

      • Added -print0 to find
      • Quoted the wildcard patterns
      • Preserved file extensions using ${file##*.}

      Try this and let me know if it works!

    • SchwertImStein@lemmy.dbzer0.com
      link
      fedilink
      English
      arrow-up
      2
      ·
      4 hours ago
      find ./ -type f ( -iname '*.jpg' -o -iname '*.png' ) -print0 |
      while IFS= read -r -d '' file; do
        echo "in loop"
        echo "$file"
        dir=$(dirname "$file")
        base=$(basename "$file")
        echo "'$dir'/'$base'"
        new_name="$dir/$(uuidgen -r)"
        echo "Renaming ${file} to ${new_name}"
        # mv "$file" "$new_name"
      done
      

      That’s what perplexity gave me after copy pasting the post.