benjamin benjamin - 10 months ago 47
Perl Question

perl function to replace all spaces in file and directory names with periods

I'm not a programmer by trade so I just wanted to put that disclaimer out there. And there is probably a better way of doing this but this is the way I started and I'd like to know why this isn't working.

I have a perl function for replacing spaces with periods in filenames and directories:

sub rm_space {
for(@_) {
# for directory or file if it contains spaces, replace with periods
if(m/^(.*(.(?=\s).).*)$/) {
$new = $_;
$new =~ s/ /\./g;
move($_, $new);
if(-d) {
# if $_ is a directory, list contents and repeat
@arr = `ls -1d $_/*`;

The function will work on everything in the first array (@_) but will not work recursively on the second unless the directory from the first array didn't already contain spaces.

Answer Source

To process files recursively in Perl, use File::Find:

use warnings;
use strict;

use File::Find;

my %rename;
find(\&spaces2dots, shift);
for my $old (sort { length $b <=> length $a } keys %rename) {
    rename $old, $rename{$old}
        or warn "Cannot rename $old to $rename{$old}.\n";

sub spaces2dots {
    ( my $new = $File::Find::name ) =~ s{ (?!.*/)}{.}g;
    $rename{$File::Find::name} = $new;

The files are sorted by filename length starting from the longest one, and only spaces after the last / are replaced in each step, so file named a b/c d/e f is renamed to a b/c d/e.f, then its parent directory is renamed to a b/c.d, and finally the a b directory is renamed to a.b.

For completeness, here's the Makefile I used for testing:

run: clean
    mkdir 'a b' 'c d'
    mkdir 'a b'/'A B' 'a b'/'C D'
    mkdir 'a b'/'C D'/'e F'
    touch 'e f' 'a b'/'E F' 'a b'/'C D'/'e F'/'g H' .

    rm -rf ???