ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
I am just starting to learn Perl and I am trying to write a script that will go through all of my music files and do the following:
1) Change all spaces in file names into underscores.
2) Change all uppercase letters file names into lowercase.
3) Find all .m4a files in my music directory && convert them into .mp3 format
4) Remove the old .m4a files.
I understand there is probably software out there, already designed to do this, but I am just writing this as a programming exercise to learn better.
Below is what I have come up with so far. Bear with me if there is something stupid I've written here -- I'm still learning.
Anyhow, I am worried about running any scripts that I have written that rename or remove files, because I am not sure how things are interpolated in the backticks before running the command (backticks being the little tilted single-quote looking things around the command to be run...), and don't want a weird character to be fed into the regex, and have it start wiping out files I don't want it to.
Here is what I have so far:
Code:
#!/usr/bin/perl -w
use File::Find;
$music_dir="/mnt/storage/music";
find(\&Wanted, $music_dir);
sub Wanted{
$_ eq "." and next;
$_ eq ".." and next;
my $new_filename = $_;
#Change all letters to lowercase
$new_filename =~ s/(\w+)/\L$1/g;
#Change whitespace to underscore
$new_filename =~ s/(\s+)/_/g;
rename $File::Find::name, "$File::Find::dir/$new_filename";
#Then convert it to the proper format && remove the old copy.
if ($new_filename =~ /(\w+)[.]{1}m4a$/){
`faad $File::Find:dir/$new_filename`
or die "Couldn't transcode $File::Find::dir/$new_filename from .m4a to .wav: $!";
`lame -m j $new_filename $1.mp3`
or die "Couldn't transcode $File::Find::dir/$new_filename from .wav to .mp3: $!";
`rm $File::Find::dir/$new_filename`
or die "Couldn't remove $File::Find::dir/$new_filename: $!";
`rm $File::Find::dir/$1.wav`
or die "Couldn't remove $File::Find::dir/$new_filename: $!";
}
}
Does this look like it will work? I am especially worried about my regular expressions. Do they look sensible? Anybody have any suggestions on how to make it work better?
Also, if anyone has some good documentation on what goes on inside those backticks, I'd love to hear all about it...
Thanks,
Mr. Snorfles
Last edited by mistersnorfles; 08-18-2007 at 10:24 PM.
That thread addresses some of your questions. You situation is a little different because you're dealing with m4a files, but it looks to me like you have that under control.
The "backtick" function has been deprecated, and (for me) using the new format makes it easier to understand. Replace the backtics with $() ... like this: $ echo $(uname -r)
Instread of a regex, I'd used the lc() fn to convert case. http://perldoc.perl.org/functions/lc.html
Also, mandate
use locale;
at the top of your prog to deal with any accented chars (even if you don't have any, it's good practice)
Also,
use strict;
forces declarations and traps some other possible errors. Again, it's best practice to use that and the "-w" switch together. They do different checks.
To do a test compile without running prog do
perl -wc yourprog.pl
which will just do a test compile and syntax check.
The other thing is to comment out the rm cmds until you've tested the rest.
Use the unlink() fn instead of rm. http://perldoc.perl.org/functions/unlink.html
Yeah I figured there was a lowercase function, but I just didn't know what it was called. I agree, lc() will definitely be an easier way to do this. Thanks Chris.
By the way, as fan as using unlink() vs rm, what are the benefits?
Same with $() vs `command` -- why is the former the better choice?
Thanks for the help folks.
--Mr. Snorfles
Last edited by mistersnorfles; 08-19-2007 at 08:38 PM.
Reason: Found the answer in the link you gave me...
unlink - give it a scalar containing full path, or just filename if perl prog is in same dir as file to remove.
If you don't require to trap/gather the output from external cmds, you can use system() http://perldoc.perl.org/functions/system.html
The doc page explains this more fully.
Personally, I'd use something like the following instead of File::Find:
Code:
opendir(DIR, $dirname) or die "can't opendir $dirname: $!";
while (defined($file = readdir(DIR)))
{
next if $file =~ /^\.\.?$/; # skip . and ..
# do something with "$dirname/$file"
}
closedir(DIR);
Thanks again for all the help. I made the suggested modifications --except for $() which I couldn't figure out -- and everything worked wonderfully. Here was the script I ended up running:
Code:
#!/usr/bin/perl -w
use File::Find;
use locale;
use strict;
my $music_dir="/mnt/storage/music";
find(\&Wanted, $music_dir);
sub Wanted{
$_ eq "." and next;
$_ eq ".." and next;
my $new_filename = $_;
#Change all letters to lowercase
$new_filename=lc($new_filename);
#Change whitespace to underscore
$new_filename =~ s/(\s+)/_/g;
rename( $File::Find::name, "$File::Find::dir/$new_filename");
#Then convert it to the proper format && remove the old copy.
if ($new_filename =~ /([\w',]+)[.]{1}m4a$/){
my $filename_no_ext = $1;
(system("faad", "$File::Find::dir/$new_filename") or $new_filename =~ s/m4a$/wav/)
or die "Couldn't transcode $File::Find::dir/$new_filename from .m4a to .wav: $!";
system("lame", "-m","j", "$new_filename", "$filename_no_ext.mp3")
and die "Couldn't transcode $File::Find::dir/$new_filename from .wav to .mp3: $!";
unlink("$File::Find::dir/$new_filename")
or die "Couldn't remove $File::Find::dir/$new_filename: $!";
unlink("$File::Find::dir/$filename_no_ext.m4a")
or die "Couldn't remove $File::Find::dir/$new_filename: $!";
}
}
Went off without a hitch...
Thanks,
Mr. Snorfles
Last edited by mistersnorfles; 08-19-2007 at 10:01 PM.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.