1

在我拥有的 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 匹配?

4

2 回答 2

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启用备份选项的情况下运行它,直到您知道它可以按预期与您的文件一起使用。

于 2013-04-17T13:58:51.460 回答
0

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

首先,你有一个无用的反引号。改为使用system

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

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

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

或者您可以完全避免使用外壳:

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

关于你的问题。

-p导致 Perl 用

while (<>) {
   ... -e ...
} continue {
   print;
}

像这样,

/foo(\r\nfoo2)/

或更灵活

/foo(\s*\nfoo2)/

因为您还没有阅读,所以不可能匹配foo2。您可以<>通过首先执行来读取整个文件local $/;,这可以通过添加-0777get

$/ = 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);
于 2013-04-17T14:51:33.850 回答