3

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

rename 'perl-regex' list-of-files

所以这是我放在一起的内容,但它不会重命名任何文件($new 始终与 $file 相同):

#!/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";
    }
}

就好像我没有通过正则表达式,如果我硬编码它

$new =~ s/TMP/tmp;

它会工作得很好......有什么想法吗?

4

4 回答 4

3
$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 $@;
于 2013-02-03T21:45:38.087 回答
2

你不能把整个句子s/TMP/tmp;放在一个变量中。但是,您可以执行类似的操作

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

$find成为您的正则表达式以及$replace您想要替换匹配项的内容。

如果你仍然想通过整个句子,你可能想看看eval()

于 2013-02-03T20:25:21.503 回答
2

有两种方法可以优雅地解决这个问题

  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): 在旧的 perls 中没有嵌套的正则表达式

  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. 这会跳过所有以点开头的文件,注册一个全局变量$i,并在每个文件名前面放置一个从一开始向上计数的数字,然后更改扩展名。然后我们$_在最后一条语句中返回。

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

    这可能是相当灵活的,并且不会过于低效。

于 2013-02-03T21:45:22.333 回答
2

好吧,它已经是一个 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.

于 2013-02-03T22:26:13.527 回答