我不是程序员,所以我只是想把免责声明放在那里。也许有更好的方法可以做到这一点,但这就是我开始的方式,我想知道为什么这不起作用。
我有一个perl函数,用于在文件名和目录中用句点替换空格:
sub rm_space {
for(@_) {
# for directory or file if it contains spaces, replace with periods
chomp;
if(m/^(.*(.(?=s).).*)$/) {
$new = $_;
$new =~ s/ /./g;
move($_, $new);
}
if(-d) {
# if $_ is a directory, list contents and repeat
@arr = `ls -1d $_/*`;
rm_space(@arr);
}
}
}
该函数将处理第一个数组(@_(中的所有内容,但不会递归处理第二个数组,除非第一个数组中的目录尚未包含空格。
要在Perl中递归处理文件,请使用File::Find:
#!/usr/bin/perl
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;
}
文件按文件名长度排序,从最长的开始,每一步只替换最后一个/
之后的空格,所以名为a b/c d/e f
的文件被重命名为a b/c d/e.f
,然后其父目录被重命名为a b/c.d
,最后a b
目录被重命名成a.b
。
为了完整起见,以下是我用于测试的Makefile:
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'
40115711.pl .
find
clean:
rm -rf ???
#!/usr/bin/env perl
use strict;
use warnings;
sub rm_space
{
foreach my $file_or_dir (@_) {
my $with_dots = $file_or_dir;
if ( $with_dots =~ tr/ /./ ) {
# only called when replacement occurred
rename( $file_or_dir, $with_dots );
}
if ( -d $with_dots ) {
my @arr = glob("$with_dots/*");
rm_space(@arr);
}
}
}
rm_space( glob("start_dir/*") );
您首先将目录从例如dir with spaces
重命名为dir.with.spaces
,然后深入dir with spaces
。那个目录已经不见了。您需要两个变量,一个用于旧名称一个用于新名称,然后在新名称上调用rm_space
。
此外,强烈建议use strict;
和use warnings;
避免常见错误(如打字错误(或未定义变量的使用(。
我将对ls
的调用替换为对glob
的调用。优点是你不必关心然后在名称中添加空格。您的ls -1d dir with spaces/*
一定失败了。
我还使用了显式变量(而不是隐式$_
(,因为有时很难弄清楚CCD_ 17实际包含的内容。