2015-01-24 2 views
1

Я хотел бы знать, что эквивалентный код, который Perl запускает при выполнении с опциями perl -pi -e?Что именно делает perl -pi -e?

На некоторых SO вопрос я могу прочитать:

while (<>) { 
    ...  # your script goes here 
} continue { 
    print; 
} 

Но этот пример не показывает ту часть, где будет сохранен файл.

Как Perl определяет EOL? Прикосновение к файлу, когда никаких изменений не произошло? Например, если у меня есть старый файл MAC (только \r). Как это относится к s/^foo/bar/gm?

Я пытался использовать отладчик Perl, но это действительно не помогает. Так что я просто пытаюсь угадать:

#!/usr/bin/env perl 

my $pattern = shift; 
map &process, @ARGV; 
# perl -pi -e PATTERN <files>... 
sub process { 
    next unless -f; 
    open my $fh, '<', $_; 
    my $extract; 
    read $fh, $extract, 1024; 
    seek &fh, 0, 0; 
    if ($extract =~ /\r\n/) { 
     $/ = "\r\n"; 
    } elsif ($extract =~ /\r[^\n]/) { 
     $/ = "\r"; 
    } else { 
     $/ = "\n"; 
    } 

    my $out = ''; 
    while(<&fh>) { 
     my $__ = $_; 

     eval $pattern; 

     my $changes = 1 if $_ ne $__; 
     $out .= $_; 
    } 

    if($changes) 
    { 
     open my $fh, '>', $_; 
     print $fh $out; 
    } 
    close &fh; 
} 

ответ

7

Вы можете проверить код на самом деле используемый Perl с основным модулем B :: Deparse. Этот модуль модуля компилятора активируется с опцией -MO=Deparse.

$ perl -MO=Deparse -p -i -e 's/X/U/' ./*.txt 
BEGIN { $^I = ""; } 
LINE: while (defined($_ = <ARGV>)) { 
    s/X/U/; 
} 
continue { 
    die "-p destination: $!\n" unless print $_; 
} 
-e syntax OK 

Таким образом Perl зацикливается над линиями в данных файлах, выполняет код с $ _ набор в линию и выводит полученный $ _.

Магическая переменная $^I установлена ​​в пустую строку. Это включает редактирование на месте. На месте редактирование описано в perldoc perlrun. Невозможно проверить, не изменился ли файл. Таким образом, измененное время отредактированного файла всегда обновляется. По-видимому, измененное время резервного файла совпадает с измененным временем исходного файла.

Используя флаг -0, вы можете установить разделитель входных записей для использования «\ r» для ваших файлов Mac.

$ perl -e "print qq{aa\raa\raa}" > t.txt 
$perl -015 -p -i.ori -e 's/a/b/' t.txt 
$cat t.txt 
ba 
$ perl -MO=Deparse -015 -p -i.ori -e 's/a/b/'.txt 
BEGIN { $^I = ".ori"; } 
BEGIN { $/ = "\r"; $\ = undef; } 
LINE: while (defined($_ = <ARGV>)) { 
    s/a/b/; 
} 
continue { 
    die "-p destination: $!\n" unless print $_; 
} 
-e syntax OK 
+0

Очень интересный ответ. Я все еще немного смущен, потому что я не вижу каких-либо '' open' или печать $ Fh $ _' заявление в этом выводе. Как Perl открыть файл? '' для меня похож на 'my @ARGV = qw/foo.txt /; my $ bar = , где я получу ошибку. Я что-то упустил? – nowox

+2

@coin I/O Раздел операторов '[perlop] (http://perldoc.perl.org/perlop.html)' имеет часть, начинающуюся с «Нулевой дескриптор файла <> является специальным», который предлагает довольно хорошее объяснение. – Slade

+2

Да, открытие и закрытие выходных файлов не отображается в выводе deparse. Оно обрабатывается магией редактирования inplace. Этот раздел для «-i» в perldoc perlrun объясняет это. 'Print $ _' можно увидеть в блоке continue. Нет $ fh, потому что магия редактирования inplace выбирает дескриптор выходного файла по умолчанию. Вы можете сделать что-то подобное с командой 'select'. '' это, как я понимаю, синониму для '<>'. – BarneySchmale

0

От perlrun documentation:

-p assumes an input loop around your script. Lines are printed. 
-i files processed by the < > construct are to be edited in place. 
-e may be used to enter a single line of script. Multiple -e commands may be given to build up a multiline script. 
+0

это не помогает много :( – nowox

Смежные вопросы