CRLF与perl -pi -e

时间:2013-04-17 13:55:37

标签: perl

在我的perl程序中,我呼吁对具有受限权限的文件进行就地编辑:

for my $file (@files) {
    `sudo perl -pi -e 's/foo(.?foo2)/bar\$1/m' '$file'`;
}

foo和foo2之间可能存在换行符,但文件使用CRLF作为换行符。如何在-pi命令中将CRLF与s /// m或s /// s匹配?

2 个答案:

答案 0 :(得分:2)

\s*怎么样?或者,如果您想要具体[\r\n]{0,2}。前者匹配0或更多的空格,后者0到2行换行或回车。您还需要使用-0777逐行模式读取文件。

或许比将多个系统命令作为单行运行更好的解决方案是创建一个带有文件列表的脚本文件,例如

system(qw(sudo perl -0777 -pi script.pl), @files);

脚本文件仅包含您的替换:

s/foo(?=\s*foo2)/bar/m;

我还用后向断言替换了反向引用$1。请注意,我建议您在没有-i开关或启用-i.bak备份选项的情况下运行此操作,直到您知道它与您的文件一致。

答案 1 :(得分:0)

在回答你的问题之前,我们先谈谈两件事。

首先,你没有使用反引号。请改用system

for my $file (@files) {
    system("sudo perl ...");
}

其次,您没有正确地将$file的内容转换为shell文字。考虑如果$file包含单引号会发生什么。修正:

use String::ShellQuote qw( shell_quote );
for my $file (@files) {
    system(shell_quote('sudo', 'perl', ..., $file));
}

或者你可以完全避免使用shell:

for my $file (@files) {
    system('sudo', 'perl', ..., $file);
}

关于你的问题。

-p导致Perl用

包装程序
while (<>) {
   ... -e ...
} continue {
   print;
}

因此,

/foo(\r\nfoo2)/

或更灵活

/foo(\s*\nfoo2)/

无法匹配,因为您尚未阅读foo2。首先执行<>可能会导致local $/;读取整个文件,这可以通过添加-0777来获取

$/ = undef;
while (<>) {
   ...[ code from -e ]...
} continue {
   print;
}

所以你需要的是:

for my $file (@files) {
    system('sudo', 'perl', '-i', '-0777pe', 's/foo(\s*\nfoo2)/bar$1/', $file);
}

或者您甚至可以避免使用for循环并使用

system('sudo', 'perl', '-i', '-0777pe', 's/foo(\s*\nfoo2)/bar$1/', @files);