Как выполнить несколько подстановок содержимого каждого файла в нескольких каталогах? - PullRequest
1 голос
/ 12 октября 2011

Мне нужно выполнить несколько замен для содержимого файлов в разных каталогах (не рекурсивно).

Например, для всех файлов в каталоге dir / foo / bar :

s/blue/red/;
s/green/yellow/;

И для всех файлов в директории / foobar / bar :

s/orange/black/;

Какой самый эффективный способ написания этого сценария?

В настоящий момент все мои сценарии замещения являются однострочными, и поэтому я совершенно не знаю, как их аккуратно интегрировать в полный сценарий.


Я включил фрагмент из моего скрипта нефункционального теста ниже, если он нужен.

opendir(DIR, $dir) or die "Cannot open directory: $!\n";
my @files = readdir(DIR);
closedir(DIR);

foreach(@files) {
    my $filename = $_;   
    open(FILE, $filename);

    while (my $data = <FILE>) {
        # Substitution lines
        }
    close(FILE);
    }

Ответы [ 3 ]

3 голосов
/ 12 октября 2011

Вы можете попытаться решить проблему с помощью однострочного perl:

perl -i".bak" -n -e 's/blue/glue/g; print;' *

Вы можете использовать много -e или альтернативно использовать много s ///.Это также создает резервную копию текущих файлов.

Надеюсь, это поможет.

0 голосов
/ 12 октября 2011

Обратный путь в каталогах, вероятно, является большим узким местом, поэтому вы должны попытаться сделать это только один раз.

find . -type f -exec perl -i".bak" -pe '
  if($ARGV =~ m%^./foo/bar/%){s/blue/red/g;s/green/yellow/g;}
  s/orange/black/ if($ARGV =~ m%^./foobar/bar/%' {} \;
0 голосов
/ 12 октября 2011

Я обновил код, чтобы он соответствовал тому, что вы хотите, вам придется использовать модуль разбирает аргументы командной строки, такие как Getopt :: Long; Я не уверен в синтаксисе, но вам нужно что-то, что позволяет вам делать массивы строк на обоих концах; я уверен, что есть лучший способ обработки аргументов, позволяющий считывать их как ключ, карту значений.

#!/usr/bin/perl
# invoke with:
# script.pl <name part to match> <name part to replace> <directory to examine> <directory to examine...>
use Getopt::Long;
my %opts = ();

... read in match keys / values ...

my $dir = shift;
while(-d $dir){
    @files_in_dir = <$dir/*>;
    foreach my $file (@files_in_dir){
        my @lines = ();
        open(my $IN, '<', $dir/$file);
        while(<$IN>){
            foreach $i (1..#@$opt{match}){
                if(/@{$opt{match}}[$i]/){
                    s/@{$opt{match}}[$i]/@{$opt{replace}}[$i]/;
                }  
            }
            push @lines, $_;
        }
        close $IN;
        open(my $OUT, '>', $dir/$file);
        print $OUT "$_" foreach(@lines);
        close $OUT;
    }
    $dir = shift;
}
...