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


You can do the entire thing as a one-liner using only
find:find ./ -type f \( -iname "*.jpg" -or -iname "*.png" \) -exec sh -c 'mv "$0" "$(uuidgen -r).${0##*.}"' {} \;Test on my machine:
phaedrus@sys76 ~/D/test> ls -lh total 0 -rw-r--r-- 1 phaedrus users 0 Dec 6 01:08 test1.jpg -rw-r--r-- 1 phaedrus users 0 Dec 6 01:08 test1.png -rw-r--r-- 1 phaedrus users 0 Dec 6 01:08 test2.jpg -rw-r--r-- 1 phaedrus users 0 Dec 6 01:08 test2.png -rw-r--r-- 1 phaedrus users 0 Dec 6 01:08 test3.jpg -rw-r--r-- 1 phaedrus users 0 Dec 6 01:08 test3.png phaedrus@sys76 ~/D/test> find ./ -type f \( -iname "*.jpg" -or -iname "*.png" \) -exec sh -c 'mv "$0" "$(uuidgen -r).${0##*.}"' {} \; phaedrus@sys76 ~/D/test> ls -lh total 0 -rw-r--r-- 1 phaedrus users 0 Dec 6 01:08 062d8954-9921-42bd-ad24-0e4ed403a5db.jpg -rw-r--r-- 1 phaedrus users 0 Dec 6 01:08 111f859f-b1fe-4488-b2bc-75585320e3a3.png -rw-r--r-- 1 phaedrus users 0 Dec 6 01:08 39b9fe4e-7a05-43c9-b30a-69e9a13aa3a9.png -rw-r--r-- 1 phaedrus users 0 Dec 6 01:08 57bda91e-49e5-43fe-8318-aeeb2e3adde7.png -rw-r--r-- 1 phaedrus users 0 Dec 6 01:08 97398eb7-54aa-488f-8fbe-0b84b5e5a50d.jpg -rw-r--r-- 1 phaedrus users 0 Dec 6 01:08 f7a13274-e2c0-4fa7-9907-c590d1280c2e.jpgbtw, Lemmy doesn’t like language specifiers in the multi-line code blocks, so it’s difficult to read all that in its current form since there are no tabs to know how you have it formatted. Makes it virtually impossible to troubleshoot your specific script.
edit: further reading on the ever useful variable expansions (
${0##*.}portion of my one-liner):https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
Interesting, the code shows up correctly for me in firefox. I wonder if that’s due to my instance?
This works perfectly! Thank you!!! In case anyone else finds themselves wondering about the ${0##*.} portion, I found this article to be very helpful. https://stackoverflow.com/questions/30980062/0-and-0-in-sh
edit: You beat me to it with your link on parameter expansion. I’ll be reading through that tonight as well. Thanks again.
If you want more help with Bash in the future, this is the best resource I’ve found in 13 years of writing bash professionally: https://mywiki.wooledge.org/EnglishFrontPage
Bash FAQs and pitfalls are the primary sections to look at there.
It might be instance related, I’m on PieFed, so perhaps the markdown implementation is different.
Also, I realized that the parameter expansion might not be straightforward and added the GNU docs on it, but looks like you found a post about it at the same time! Glad to hear it got you sorted out.
Thank you for providing the easiest and most portable answer. This will handle files with special characters perfectly unlike most of the responses here which rely on a
whileloop (to say nothing of aforloop ).Indeed, folks tend not to look into the docs enough to realize
findis a powerful tool on its own!I think the other answers were just adhering to the request (trying to troubleshoot the script as is), but I generally go for pragmatism despite not being what was actually requested.