هناك طريقة بسيطة للقيام الأكبر الملف النص البديل في المكان ؟

StackOverflow https://stackoverflow.com/questions/248668

سؤال

كنت أحاول رمز Perl إلى استبدال بعض النصوص على كافة ملفات المصدر من المشروع.أنا في حاجة إلى شيء من هذا القبيل:

perl -p -i.bak -e "s/thisgoesout/thisgoesin/gi" *.{cs,aspx,ascx}

ولكن أن يوزع كل الملفات من دليل بشكل متكرر.

أنا فقط بدأت النصي:

use File::Find::Rule;
use strict;

my @files = (File::Find::Rule->file()->name('*.cs','*.aspx','*.ascx')->in('.'));

foreach my $f (@files){
    if ($f =~ s/thisgoesout/thisgoesin/gi) {
           # In-place file editing, or something like that
    }
}

ولكن الآن أنا عالق.هناك طريقة بسيطة تحرير جميع الملفات في مكانها باستخدام بيرل?

يرجى ملاحظة أنه لا حاجة إلى الاحتفاظ بنسخة من كل تعديل الملف ؛ أنا 'م جميع subversioned =)

التحديث:حاولت هذا على Cygwin,

perl -p -i.bak -e "s/thisgoesout/thisgoesin/gi" {*,*/*,*/*/*}.{cs,aspx,ascx

ولكن يبدو أن الحجج القائمة انفجرت إلى أقصى حجم مسموح به.في الواقع أنا على أخطاء غريبة في سيغوين...

هل كانت مفيدة؟

المحلول

إذا قمت بتعيين @ARGV قبل استخدام *ARGV (ويعرف أيضا باسم الماس <>), $^I/-i سيتم العمل على هذه الملفات بدلا من ما كان المحدد في سطر الأوامر.

use File::Find::Rule;
use strict;

@ARGV = (File::Find::Rule->file()->name('*.cs', '*.aspx', '*.ascx')->in('.'));
$^I = '.bak';  # or set `-i` in the #! line or on the command-line

while (<>) {
    s/thisgoesout/thisgoesin/gi;
    print;
}

هذا يجب أن تفعل بالضبط ما تريد.

إذا كان النمط الخاص بك يمكن أن تمتد خطوط متعددة ، إضافة في undef $/; قبل <> بحيث بيرل تعمل على كل الملفات في كل مرة بدلا من خط سطرا.

نصائح أخرى

كنت قد تكون مهتمة في الملف::المعاملات::الذرية أو الملف::الصفقة

ملخص F::T::تبدو مشابهة جدا مع ما تحاول القيام به:

  # In this example, we wish to replace 
  # the word 'foo' with the word 'bar' in several files, 
  # with no risk of ending up with the replacement done 
  # in some files but not in others.

  use File::Transaction::Atomic;

  my $ft = File::Transaction::Atomic->new;

  eval {
      foreach my $file (@list_of_file_names) {
          $ft->linewise_rewrite($file, sub {
               s#\bfoo\b#bar#g;
          });
      }
  };

  if ($@) {
      $ft->revert;
      die "update aborted: $@";
  }
  else {
      $ft->commit;
  }

الزوجين أن مع الملف::العثور على كنت قد كتبت بالفعل ، يجب أن تكون على ما يرام.

يمكنك استخدام التعادل::ملف scalably الوصول إلى الملفات الكبيرة و تغيير لهم في المكان.ترى manpage (رجل 3perl التعادل::الملف).

تغيير

foreach my $f (@files){
    if ($f =~ s/thisgoesout/thisgoesin/gi) {
           #inplace file editing, or something like that
    }
}

إلى

foreach my $f (@files){
    open my $in, '<', $f;
    open my $out, '>', "$f.out";
    while (my $line = <$in>){
        chomp $line;
        $line =~ s/thisgoesout/thisgoesin/gi
        print $out "$line\n";
    }
}

هذا يفترض أن نمط لا تمتد عدة خطوط.إذا كان نمط قد تمتد خطوط, سوف تحتاج إلى ملتهم في محتويات الملف.("التهم" هو أمر شائع جدا بيرل الأجل).

كومب ليس من الضروري ، لقد تم عضك من قبل الخطوط التي لم تكن chompإيد واحدة مرات كثيرة جدا (إذا قمت بإسقاط chomp, تغيير print $out "$line\n"; إلى print $out $line;).

كذلك, يمكنك تغيير open my $out, '>', "$f.out"; إلى open my $out, '>', undef; لفتح ملف مؤقت ثم قم بنسخ هذا الملف إلى أكثر من الأصلي عند الاستبدال به.في الواقع, وخاصة إذا إلتهم في كل الملفات ، يمكنك ببساطة جعل تبديل في الذاكرة ومن ثم الكتابة فوق الملف الأصلي.ولكن لقد فعلت الكثير من الأخطاء تفعل ذلك دائما الكتابة إلى ملف جديد ، والتحقق من محتويات.


ملاحظة, أنا أصلا كان إذا ورد في هذا القانون.كان ذلك على الأرجح خاطئة.وهذا لن يكون إلا من خلال نسخ خطوط مطابقة التعبير العادي "thisgoesout" (بدلا من "thisgoesin" بالطبع) في حين صمت تلتهم بقية.

هل يمكن استخدام find:

find . -name '*.{cs,aspx,ascx}' | xargs perl -p -i.bak -e "s/thisgoesout/thisgoesin/gi"

هذه قائمة بجميع أسماء الملفات بشكل متكرر ، ثم xargs سوف اقرأ stdin و تشغيل ما تبقى من سطر الأوامر مع أسماء الملفات المرفقة في نهاية المطاف.من xargs هو أنه سيتم تشغيل سطر الأوامر أكثر من مرة إذا كان سطر الأوامر فإنه يبني يحصل على فترة طويلة جدا لتشغيل دفعة واحدة.

علما بأنني لست متأكدا ما إذا كان find تماما يفهم كل قذيفة طرق اختيار الملفات حتى لو سبق لا يعمل ثم ربما محاولة:

find . | grep -E '(cs|aspx|ascx)$' | xargs ...

عند استخدام خطوط الأنابيب مثل هذا, أود أن بناء سطر الأوامر تشغيل كل جزء على حدة قبل الانتقال إلى تأكد من أن كل برنامج هو الحصول على المدخلات يريد.حتى تستطيع تشغيل الجزء دون xargs أولا للتحقق من ذلك.

لقد خطر لي أنه على الرغم من أنك لم تقل ذلك, ربما كنت على ويندوز بسبب لواحق الملفات التي كنت تبحث عن.في هذه الحالة المذكورة أعلاه أنابيب يمكن تشغيلها باستخدام Cygwin.من الممكن أن أكتب Perl أن تفعل الشيء نفسه كما كنت بدأت القيام به ، ولكن عليك أن تفعل في مكان تحرير نفسك لأنك لا تستطيع الاستفادة من -i التبديل في هذه الحالة.

بفضل ephemient على هذا السؤال وعلى هذا الجواب, حصلت على هذا:

use File::Find::Rule;
use strict;

sub ReplaceText {
    my $regex = shift;
    my $replace = shift;

    @ARGV = (File::Find::Rule->file()->name('*.cs','*.aspx','*.ascx')->in('.'));
    $^I = '.bak';
    while (<>) {
        s/$regex/$replace->()/gie;
        print;
    }
}

ReplaceText qr/some(crazy)regexp/, sub { "some $1 text" };

الآن أستطيع حتى أن حلقة من خلال تجزئة تحتوي regexp=>الغواصات إدخالات!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top