如何使用 Perl 单行程序根据第一行模式匹配添加行?

How to use Perl one-liner to add line based on first line pattern match?

我的老板需要通过添加如下行来更改几十(数百)台主机上的特定路由文件:

10.11.0.0/16   via 172.16.2.XX dev tun0

... 其中 XX 基于同一文件第一行 "dev" 关键字之前的八位字节。

他希望它是一个自动就地编辑。现有文件的第一行如下所示:

10.12.123.0/22 via 172.16.2.24 dev tun0
10.13.234.0/23 via 172.16.2.22 dev tun0

所以结果应该是这样的:

10.12.123.0/22 via 172.16.2.24 dev tun0
10.13.234.0/23 via 172.16.2.22 dev tun0
10.11.0.0/16   via 172.16.2.24 dev tun0

...最后一行只是添加,该行的最后一个八位字节是从第一行的最后一个八位字节复制而来的。

这是我的尝试...似乎对单个文件有效:

perl -pi.bak -e '$octet =  if /(\d+)\s+dev/ and $. == 1;\
  $line="10.11.0.0/16 via 172.16.2.$octet dev tun0\n";\
  $_ = $_ . $line if eof;' "$filenames"

这是一个更安全的变体,它只附加预期的行如果在每个文件的第一行找到匹配的模式。 (它还会重置 $.,如 Сухой27 所述):

perl -pi.bak -e '$line ="10.11.0.0/16 via 172.16.2. dev tun0\n"\
  if /(\d+)\s+dev/ && $. == 1;\
  close(ARGV), $_ = $_ . $line if eof;' "$filenames"

(如果没有找到正则表达式的匹配项,则 $line 为空并且将空字符串附加到 $_ 是无害的)。

当然,您可以将它塞进一个衬里,但为什么要惩罚自己(以及必须在路上维护它的可怜的草皮)。 -i 之类的东西在程序中起作用。这是您正在寻找的基本模式。

#!/usr/bin/env perl -n -i

print $_;
if( /...whatever you want to match.../ ) {
    print "...whatever extra line you want to add...";
}

-n 表示逐行迭代,就好像程序周围有一个 while 循环。与 -p 不同,它不会自动打印该行。当然,您可以附加到 $_,但这可以让我们更好地控制。

-i 说要就地编辑文件而不是只打印到 STDOUT。

您似乎没有为每个输入文件重置行计数器 $.,而 close(ARGV) 正是这样做的,

perl -i.bak -pe'
  $octet =  if /(\d+)\s+dev/ and $. ==1;
  $_ .= "10.11.0.0/16 via 172.16.2.$octet dev tun0\n", close(ARGV) if eof;
' "$filenames"