使用Perl实现linux命令“重命名”

Mac OS X没有有用的linux命令rename ,其格式如下:

 rename 'perl-regex' list-of-files 

所以这里是我放在一起,但它不重命名任何文件($新总是一样的$文件):

 #!/usr/bin/env perl -w use strict; use File::Copy 'move'; my $regex=shift; my @files=@ARGV; for my $file (@files) { my $new=$file; $new =~ "$regex"; # this is were the problem is !!! if ($new ne $file) { print STDOUT "$file --> $new \n"; move $file, ${new} or warn "Could not rename $file to $new"; } } 

这就好像我没有通过正则expression式,如果我硬编码

 $new =~ s/TMP/tmp; 

它会工作得很好…任何想法?

 $operator = 's/TMP/tmp/'; print $operator; 

不会神奇地评估操作员,所以应该不会有什么意外的

 $operator = 's/TMP/tmp/'; $x =~ $operator; 

也不是。 如果你想评估Perl代码,你将不得不把它传递给Perl解释器。 您可以使用eval EXPR访问它。

 $operator = 's/TMP/tmp/'; eval('$x =~ '.$operator.'; 1') or die $@; 

你不能把整个句子s/TMP/tmp; 在一个变量。 但是,你可以做类似的事情

 $new =~ s/$find/$replace; 

$find你的正则表达式和$replace你想要替换的比赛。

如果你仍然想传递整个句子,你可能想看看eval() 。

有两种方法可以优雅地解决

  1. 需要两个独立的命令行参数:一个用于正则表达式,一个用于替换。 这是不雅和限制性的。

     my ($search, $replace, @files) = @ARGV; ...; my $new = $file; $new =~ s/$search/$replace/e; # the /e evals the replacement, # allowing us to interpolate vars 

    my-rename '(.*)\.txt' '@{[our $i++]}-$1.foo' *.txt 。 这允许通过字符串变量插值来执行几乎任何代码。

    (1):在老版本中没有嵌套正则表达式

  2. 只要允许任意的Perl代码,类似于perl -ne'...'-n开关的语义是当前行作为$_传递。 将文件名作为$_传递是有意义的,并且使用最后一个语句的值作为新的文件名。 这会导致类似的东西

     # somewhat tested my ($eval_content, @files) = @ARGV; my $code = eval q' sub { no strict; # could be helpful ;-) my @_out_; FILENAME: for (@_) { my $_orig_ = $_; push @_out_, [ $_orig_ => do { ' . $eval_content . q' } ]; # or # do { " . $eval_content . " }; # push @_out_, [ $_orig_, $_ ]; # if you want to use $_ as out-argument (like -p). # Can lead to more concise code. } return @_out_; } '; die "Eval error: $@" if $@; for my $rename ($code->(@files)) { my ($from, $to) = @$rename; ... } 

    这可以像my-rename 'next FILENAME if /^\./; our $i++; s/(.*)\.txt/$i-$1.foo/; $_' *.txt my-rename 'next FILENAME if /^\./; our $i++; s/(.*)\.txt/$i-$1.foo/; $_' *.txt my-rename 'next FILENAME if /^\./; our $i++; s/(.*)\.txt/$i-$1.foo/; $_' *.txt 。 这将跳过以点开头的所有文件,注册一个全局变量$i ,并从每个文件名之前的一个向上计数,并更改扩展名。 然后我们在最后一个语句中返回$_

    循环构建了原始文件和新文件名的对,可以在第二个循环中处理。

    这可能是相当灵活的,而不是太低效。

那么,它已经是一个Perl实用程序,它在CPAN上: http : //cpan.me/rename 。 您可以直接使用该实用程序File :: Rename附带的模块:

 #!/usr/bin/env perl use File::Rename qw(rename); rename @ARGV, sub { s/TMP/tmp/ }, 'verbose'; 

其他可能性是连接模块和该分发的脚本,并把结果文件放到你的$PATH