Perl 正则表达式 - 仅打印修改后的行(如 sed -n 's///p')

Perl regex - print only modified line (like sed -n 's///p')

我有一个命令可以输出以下格式的文本:

misc1=poiuyt
var1=qwerty
var2=asdfgh
var3=zxcvbn
misc2=lkjhgf

等我需要将 var1、var2 和 var3 的值获取到 perl 脚本中的变量中。

如果我要编写 shell 脚本,我会这样做:

OUTPUT=$(command | grep '^var-')
VAR1=$(echo "${OUTPUT}" | sed -ne 's/^var1=\(.*\)$//p')
VAR2=$(echo "${OUTPUT}" | sed -ne 's/^var2=\(.*\)$//p')
VAR3=$(echo "${OUTPUT}" | sed -ne 's/^var3=\(.*\)$//p')

用我想要的基本内容填充 OUTPUT(因此我不必多次 运行 原始命令),然后我可以使用 sed VAR1 = [=33 提取每个值=],等等

我过去使用过 perl,但我很生疏。这是我能想到的最好的:

my $output = `command | grep '^var'`;
(my $var1 = $output) =~ s/\bvar1=(.*)\b//m;
print $var1

这正确匹配并引用了 var1 的值,但它也 returns 不匹配的行,因此 $var1 等于:

qwerty
var2=asdfgh
var3=zxcvbn

使用 sed 我可以告诉它只打印修改过的行。有没有办法在 perl 中做类似的事情?我在 perl 中找不到与 sed 的 p 修饰符等价的东西。

相反,有没有更好的方法从每一行中提取那些子字符串?我确定我可以匹配匹配每一行并拆分内容或类似的东西,但我试图坚持使用正则表达式,因为这是我通常在 perl 之外解决这个问题的方式。

感谢任何指导。我确定我遗漏了一些相对简单的东西。

一种方式

my @values = map { /\bvar(?:1|2|3)\s*=\s*(.*)/ ?  : () } qx(command);

qx operator ("backticks") returns a list of all lines of output when used in list context, here imposed by map。 (在标量上下文中,它 returns 所有输出都在一个字符串中,可能是多行。)然后 map 提取想要的值:其中的三元运算符 returns 捕获,或者一个空列表不匹配(因此过滤掉这些行)。请适当调整正则表达式。

或者可以将其分解,获取所有输出,然后过滤需要的行,然后解析它们。这允许进行更细微的分阶段处理。然后还有用于管理外部命令的库,这些库使更多的工作变得更好。


对问题中显示的 Perl 尝试的评论

由于反引号被分配给标量,因此它处于标量上下文中,因此 returns 所有输出都在一个字符串中,这里是多行。然后下面的正则表达式将 var1=(.*) 替换为 </code>,留下接下来的两行,因为 <code>. 不匹配换行符,所以 .* 在第一个换行符处停止。

因此您需要修改该正则表达式以匹配所有其余部分,以便将其全部替换为捕获 </code>。但是对于其他变量,模式必须不同。或者,可以用所有三个 <code>var 值替换输入字符串,但是这样你就会得到一个包含这三个值的字符串。

总而言之:在这里使用替换 (s///) 是不合适的——只需使用匹配,m//.

因为在列表上下文中匹配运算符也returns所有匹配另一种方式是

my @values = qx(command) =~ /\bvar(?:1|2|3)\s*=\s*(.*)/g;

现在是正则表达式的 boundqx 在标量上下文中,因此它 returns 是一个(此处为多行)字符串,然后由正则表达式匹配。使用 /g 修饰符,模式通过该字符串保持匹配,捕获所有想要的值(而不是其他)。 . 不匹配换行符所以 .* 在第一个换行符处停止的事实现在很有用。

再次提醒,请根据实际问题调整正则表达式。


另一个需求出现了,即捕获变量的实际名称及其值。然后在名称周围添加捕获括号,并分配给哈希

my %val = map { /\b(var(?:1|2|3))\s*=\s*(.*)/ ? (, ) : () } qx(command);

my %val = qx(command) =~ /\b(var(?:1|2|3))\s*=\s*(.*)/g;

现在mapcommandreturns的每一行输出一对var-name+值,而这样的对列表可以赋值给一个哈希。在第二种情况下,后续匹配(在 /g 下)也是如此..

在标量上下文中,s///s///g return 是否找到匹配项。所以你可以使用

print $s if $s =~ s///;