3

renameMac Os Xには、次の形式の便利な linux コマンドがありません。

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

これをエレガントに解決するには2つの方法があります

  1. 2 つの別個のコマンド ライン引数が必要です。1 つは正規表現用で、もう 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): 古い perl にはネストされた正規表現はありません

  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各ファイル名の前に 1 から数えた数字が付けられ、拡張子が変更されます。$_次に、最後のステートメントに戻ります。

    ループは元のファイル名と新しいファイル名のペアを作成し、2 番目のループで処理できます。

    これはおそらく非常に柔軟であり、過度に非効率的ではありません。

于 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';

他の可能性としては、そのディストリビューションのモジュールとスクリプトを連結し、結果のファイルを .xml ファイルのどこかに置くことです$PATH

于 2013-02-03T22:26:13.527 に答える