Perl正则提取zpool status字段仅返回匹配标识1问题求解
问题原因
Perl 正则匹配的返回值由上下文决定:当匹配操作在标量上下文(即直接将匹配结果赋值给单个标量变量)下,只会返回布尔类型的匹配结果(匹配成功返回1,失败返回空值),你看到的1就是匹配成功的标识,而非捕获组的内容。
解决方法
你可以通过两种方式拿到捕获组的内容:
方法1:使用内置捕获变量$1
匹配成功后,第一个捕获组的内容会自动存入内置变量$1,第二个捕获组存入$2,以此类推,直接取对应变量的值即可:
my $strCmdErg = `/sbin/zpool status`; my ($poolname, $state); if ($strCmdErg =~ /pool:\s(.*$)/m) { $poolname = $1; } print "PoolName: $poolname \n"; if ($strCmdErg =~ /^\s*state:\s(.*$)/m) { $state = $1; } print "Status: $state \n";
注意:不需要加
g修饰符,你只需要匹配第一次出现的对应字段即可,加g会开启全局匹配迭代,不符合单字段提取的需求。
方法2:将匹配放入列表上下文
给接收变量外层加上括号,即可将匹配操作切换到列表上下文,此时返回值就是所有捕获组的内容,可以直接赋值:
my ($poolname) = $strCmdErg =~ /pool:\s(.*$)/m; print "PoolName: $poolname \n"; my ($state) = $strCmdErg =~ /^\s*state:\s(.*$)/m; print "Status: $state \n";
跨多行字段的提取方案
对于status、action、config这类跨多行的字段,可以加上s修饰符让.匹配换行符,配合正向预查定位到下一个字段的开头即可完成提取,完整示例如下:
my $strCmdErg = `/sbin/zpool status`; # 提取全部所需字段 my ($pool) = $strCmdErg =~ /^\s*pool:\s(.*)$/m; my ($state) = $strCmdErg =~ /^\s*state:\s(.*)$/m; my ($status) = $strCmdErg =~ /^\s*status:\s(.*?)(?=\n\s*action:)/ms; $status =~ s/\s+/ /g; # 替换换行和多余缩进为空格,优化可读性 my ($action) = $strCmdErg =~ /^\s*action:\s(.*?)(?=\n\s*scan:)/ms; $action =~ s/\s+/ /g; my ($scan) = $strCmdErg =~ /^\s*scan:\s(.*)$/m; my ($config) = $strCmdErg =~ /^\s*config:\s(.*?)(?=\n\s*errors:)/ms; my ($errors) = $strCmdErg =~ /^\s*errors:\s(.*)$/m; # 输出结果 print "Pool: $pool\n"; print "State: $state\n"; print "Status: $status\n"; print "Action: $action\n"; print "Scan: $scan\n"; print "Config:\n$config\n"; print "Errors: $errors\n";
内容的提问来源于stack exchange,提问作者Christian Timm
相关产品推荐
相关产品推荐

