You are not logged in.
Pages: 1
In order to clean up the filenames in my music directory, I've been working on writing a script to rename files automagically for me. However, I'm having troubles with recursion in this script. If it changes the name of a directory, it does not alter the names of files or directories beneath the changed directory. To demonstrate the problem, I set up a test directory, where the only things that will be changed are spaces in filenames.
The script (file-rename.pl):
#!/usr/bin/perl -w
use strict;
chomp(@ARGV = <STDIN>) unless @ARGV;
foreach my $filename (@ARGV)
{
my $orig_filename = $filename;
$filename =~ tr/ /\-/;
$filename =~ tr/[{</(/;
$filename =~ tr/]}>/)/;
$filename =~ s/&/and/;
$filename =~ tr{ a-zA-Z0-9.\-/_()}{}cd;
#$filename =~ tr/A-Z/a-z/;
unless ($filename eq $orig_filename)
{
print "About to rename $orig_filename to $filename\n";
if (-e $filename)
{
print "There already exists a file named $filename\n";
print "Skipping the rename – you will have to do it manually\n";
}
else
{
rename($orig_filename, $filename);
}
}
}
The test directory (before):
$ ls -R
.:
artist
artist with spaces in name
./artist:
album
album with spaces in name
./artist/album:
song
song with spaces
./artist/album with spaces in name:
song
song with spaces
./artist with spaces in name:
album
album with spaces in name
./artist with spaces in name/album:
song
song with spaces
./artist with spaces in name/album with spaces in name:
song
song with spaces
The find command to run the script and rename the files and directories:
$ find . -depth -print0 | xargs -0 /location/of/file-rename.pl
The test directory (after)
$ ls -R
.:
artist
artist-with-spaces-in-name
file-rename-output.txt
./artist:
album
album-with-spaces-in-name
./artist/album:
song
song-with-spaces
./artist/album-with-spaces-in-name:
song
song with spaces
./artist-with-spaces-in-name:
album
album with spaces in name
./artist-with-spaces-in-name/album:
song
song with spaces
./artist-with-spaces-in-name/album with spaces in name:
song
song with spaces
The output of the script:
About to rename ./artist with spaces in name/album with spaces in name/song with spaces to ./artist-with-spaces-in-name/album-with-spaces-in-name/song-with-spaces
About to rename ./artist with spaces in name/album with spaces in name/song to ./artist-with-spaces-in-name/album-with-spaces-in-name/song
About to rename ./artist with spaces in name/album with spaces in name to ./artist-with-spaces-in-name/album-with-spaces-in-name
About to rename ./artist with spaces in name/album/song with spaces to ./artist-with-spaces-in-name/album/song-with-spaces
About to rename ./artist with spaces in name/album/song to ./artist-with-spaces-in-name/album/song
About to rename ./artist with spaces in name/album to ./artist-with-spaces-in-name/album
About to rename ./artist with spaces in name to ./artist-with-spaces-in-name
About to rename ./artist/album with spaces in name/song with spaces to ./artist/album-with-spaces-in-name/song-with-spaces
About to rename ./artist/album with spaces in name/song to ./artist/album-with-spaces-in-name/song
About to rename ./artist/album with spaces in name to ./artist/album-with-spaces-in-name
About to rename ./artist/album/song with spaces to ./artist/album/song-with-spaces
I don't understand why this is only renaming the highest level that needs renaming, rather than renaming all of the files and directories. Why isn't this code doing what I want it to, and what do I need to change so that it alters the names of all files and directories in one fell swoop?
Offline
The Rename command can only rename one part of a path at a time. So trying to rename "./artist with spaces in name/album with spaces in name/song with spaces" to "./artist-with-spaces-in-name/album-with-spaces-in-name/song-with-spaces" results in an error. Next time make sure to check return values of functions like rename. A simple "... or die;" would be enough.
The easiest solution to your problem would be an outer loop, maybe in the shell. Something like:
for i in `seq 1 $MAX`; do find . -maxdepth $i | /location/of/file-rename.pl; done
Just make sure to determine the maximum depth ($MAX) of your directory structure before.
EDIT: Please just forget what I've said about using xargs...
Last edited by ber_t (2010-07-19 19:22:08)
Offline
i have a similar script in bash. what you should do is the following,
split the arguments into dirname/basename, define just the newbasename (leaving dirname alone), and mv/rename dirname/basename to dirname/newbasename.
by passing the arguments in with the -depth flag, you'll work your way up the tree operating on one level at a time, renaming everything correctly.
for reference:
translate() {
tr -d '\n' | tr -d '\t' | tr -d \' | tr -d \" |\
sed -r -e 's/.*/\L&/g' \
-e 's/[ -]/_/g' \
-e 's/_+/_/g' \
-e 's/^_|_$//g'
}
rfile() {
local dir old new
dir="$(dirname "$1")"
old="$(basename "$1")"
new="$(echo $old | translate)"
if [[ "$old" != "$new" ]]; then
if $fake; then
echo "$dir/$old --> $dir/$new"
else
mv -iv "$dir/$old" "$dir/$new"
fi
fi
}
rdir() {
local dir
while IFS='' read -d '' -r dir; do
rfile "$dir"
done < <(find "$1" -depth -print0)
}
(just the interesting parts)
Last edited by brisbin33 (2010-07-19 21:43:07)
//github/
Offline
Pages: 1