I want to list a bunch of filenames via find
, pipe them through a utility (let's call this util
) which outputs a new name for each input name, and then rename each file from the old name to the new.
The most basic solution would be this:
find . -print0 | while IFS= read -d '' -r old_name; do
new_name="$(echo "$file" | util)"
mv "$old_name" "$new_name"
done
The problem with this approach is that util
is too slow to fire up for each filename separately. So the solution is to launch util
only once and pipe all the filenames through this single process:
find . -print0 >old_names
util <old_names >new_names
exec {old_fd}<old_names
exec {new_fd}<new_names
while IFS= read -d '' -r old_name <&$old_fd &&
IFS= read -d '' -r new_name <&$new_fd; do
mv "$old_name" "$new_name"
done
This will launch util
only once, on the other hand it's no longer a pipeline: we have to list all the files into a tmp file, run util
on this tmp file to get another tmp file, and only then do we actually start the renaming...
I've tried the following to do it in a pipelined way:
mkfifo old_names new_names
find . -print0 | tee old_names | util >new_names &
exec {old_fd}<old_names
exec {new_fd}<new_names
while IFS= read -d '' -r old_name <&$old_fd &&
IFS= read -d '' -r new_name <&$new_fd; do
mv "$old_name" "$new_name"
done
Unfortunately this can deadlock depending on how util
does input/output buffering...
So my question is: what's the proper way of doing this in bash?
util
), you may be able to userename
(the one by Larry Wall).