2

我正在尝试替换多个文件中的字符串。但只有第一个文件被替换。代码是:

perl -pi -e 's/(^<section_begin>.*\s+$)/\1<expand>\n/ if $.==1' *exp`

grep -iw "expand" *exp
a3exp:<expand>

如果我对单个文件使用相同的命令,它就可以工作:

perl -pi -e 's/(^<section_begin>.*\s+$)/\1<expand>\n/ if $.==1' n2exp
grep -iw "expand" *exp
a3exp:<expand>
n2exp:<expand>

你能帮我解决这个问题吗?

4

5 回答 5

4

根据perlvar

美元。在文件句柄关闭时重置,但在打开的文件句柄在没有干预 close() 的情况下重新打开时不会重置。

因为“<>”从不明确关闭,所以ARGV 文件中的行号会增加(但请参见 eof 中的示例)。

(添加了第二个重点)

当您使用-p,时,@ARGV设置为您在命令行中传递的文件列表。由于$.在您转到下一个文件时不会重置,因此对于第一个文件它只会等于 1。您可以通过简单地打印来查看$.

$ echo foo > foo
$ echo bar > bar
$ perl -pe 'print "$. "' *
1 bar
2 foo

(with -plines 是自动打印的,所以在上面的例子中,每行的内容都打印在 的值旁边$.

如果您按照mpapec 的建议移动到下一个文件时close使用特殊文件句柄,则其行为将与您预期的一样:ARGV$.

$ perl -pe 'print "$. "; close ARGV if eof' *
1 bar
1 foo

有关更多详细信息和几​​个很好的示例,请参阅eof 的文档。

于 2013-10-16T15:39:41.240 回答
3

通过关闭ARGV文件句柄,行计数器$.被重置。

http://perldoc.perl.org/perlvar.html#ARGV

在@ARGV 中迭代命令行文件名的特殊文件句柄

因此,您需要在eof()达到时显式关闭文件,

perl -pi -e'
  s/(^<section_begin>.*\s+$)/\1<expand>\n/ if $.==1;
  close ARGV if eof;
' *exp
于 2013-10-16T15:49:43.423 回答
2

Unix shell 有很多工具可以解决这个问题。有:find_-exec

find . -name \*exp -exec perl -pi -e '... if $.==1' {} \;

或老式for循环。看起来bash

for file in *exp
do
    perl -pi -e '... if $.==1' file
done
于 2013-10-16T15:41:34.617 回答
2

您可以使用eofeof(ARG)来检测每个文件的结尾并$.相应地重置。

从文档

在 while (<>) 循环中,eof 或 eof(ARGV) 可用于检测每个文件的结尾,而 eof() 将仅检测最后一个文件的结尾。例子:

# reset line numbering on each input file
while (<>) {
    next if /^\s*#/;  # skip comments
    print "$.\t$_";
} continue {
    close ARGV if eof;  # Not eof()!
}

http://perldoc.perl.org/functions/eof.html

于 2013-10-16T15:46:09.173 回答
0

我认为您的 if $.==1 正在吸引您。这是处理的行:您告诉它只处理输入的第一行。

于 2013-10-16T16:01:40.530 回答