bsb has asked for the wisdom of the Perl Monks concerning the following question:

$ rename Usage: rename [-v] perlexpr [filenames]
Has anyone fine-tuned an expression to tidy up shell unfriendly filenames with rename? eg.
$ rename -v '$_=lc;s/[^\w.]+/_/g' * The Pogues - Beer, Beer, Beer (Irish drinking song).mp3 renamed as the +_pogues_beer_beer_beer_irish_drinking_song_.mp3
This is a start, but I'd prefer the ' - ' to become '-', there's the trailing "_", and there's no doubt more problem cases to be found. Before I started trying to DWIM for 98% of cases I figured someone else is bound to have been there before me.

Anyone solved this already..?

Thanks,

Replies are listed 'Best First'.
Re: Clean filenames with /usr/bin/rename
by thinker (Parson) on Jun 17, 2003 at 07:59 UTC
    Hi bsb,

    The following should rename all the files in the current directory in the fashion you wish.
    perl -e 'for (<*>){ my $f= $_; tr/, -/_/s; rename $f, $_}'

    I hope this helps
    thinker

    Update Whoops, forgot the lower case. Quick fix.
    perl -e 'for (<*>){ my $f= $_; tr/, -/_/s; tr/A-Z/a-z/; rename $f, $_} +'
      Thanks but the program already exists and it's in Perl:
      $ head -n 4 `which rename` #!/usr/bin/perl -w # # This script was developed by Robin Barker (Robin.Barker@npl.co.uk), # from Larry Wall's original script eg/rename from the perl source.
      I just need a new improved expression that catches all stupid file names and converts them to something sensible. The original post does it ok, I'd hoped someone had a thoroughly tested expression ready to post.

        Let me try it again. See sub sanitize for the matching pattern in various s///, in the referenced program, that i consider fit the mold of unholy names on unix. You could then round up all the matching regexen to create one regex for rename.

Re: Clean filenames with /usr/bin/rename
by parv (Parson) on Jun 17, 2003 at 08:27 UTC
Soln: Clean filenames with /usr/bin/rename
by bsb (Priest) on Jun 20, 2003 at 00:59 UTC
    Provisional solution, that is.
    $ rename -v "\$_=lc;s/&/ and /g;y/()'/--/sd;s/(?:(\.)|(-)|[\W_])+/\$1| +|\$2||'_'/ge" *
    Shell quoting is nasty. The unprotected perl expression is:
    $_=lc;s/&/ and /g;y/()'/--/sd;s/(?:(\.)|(-)|[\W_])+/$1||$2||'_'/ge;
    I took the '&' handling from here and parv's preferences for '.' then '-' then '_' when grouping but with my own (re)implementation. My test data was pretty minimal and I'd welcome improvements or even better test cases.

    Brad

    my @f = ( 'Godspeed - Sunshine and Gasoline.mp3', 'Pogues - Token Celtic Drinking Song.mp3', 'The Pogues - Beer, Beer, Beer (Irish drinking song).mp3', 'Hell\'s Ditch', 'One&Two.mp3', 'A!! ...--B._._.C_-___-_D-._.-E', ); + for (@f) { print; $_=lc;s/&/ and /g;y/()'/--/sd; print; s/(?:(\.)|(-)|[\W_])+/$1||$2||'_'/ge; print; }
    Here's how I use it in the 'clean_name' script
    #!/usr/bin/env perl # I couldn't work out how to escape this for a shell alias my $cmd = join '', split /\n/, <<'CMDS'; $_=lc;s/&/ and /g; y/()'/--/sd; s/(?:(\.)|(-)|[\W_])+/$1||$2||'_'/ge; s/^[._-]//; s/[._-]$//; CMDS system('rename','-v',$cmd, @ARGV);