【问题标题】:Complex regex - works in Powershell, not in Bash复杂的正则表达式 - 在 Powershell 中工作,而不是在 Bash 中
【发布时间】:2019-04-30 05:50:59
【问题描述】:

以下代码是我为 Solarwinds 解析 Netbackup 命令输出的一小部分代码。这对我们的 Windows 机器来说很好,但我们的一些机器是 RHEL。

我正在尝试将以下代码转换为可在 RHEL 4.X 上使用的代码,但我在解析正则表达式时遇到了麻烦。显然,下面的代码有一些字符转义以用于 Powershell,我已经对这些字符进行了转义以用于 Shell。

我对 Shell 还不是很了解,但我会在 Powershell 代码下面发布我的一部分 Shell 代码。

$output = ./bpdbjobs

$Results = @()
$ColumnName = @()

foreach ($match in $OUTPUT) {
   $matches = $null
   $match -match "(?<jobID>\d+)?\s+(?<Type>(\b[^\d\W]+\b)|(\b[^\d\W]+\b\s+\b[^\d\W]+\b))?\s+(?<State>(Done)|(Active)|(\w+`-\w+`-\w+))?\s+(?<Status>\d+)?\s+(?<Policy>(\w+)|(\w+`_\w+)|(\w+`_\w+`_\w+))?\s+(?<Schedule>(\b[^\d\W]+\b\-\b[^\d\W]+\b)|(\-)|(\b[^\d\W]+\b))?\s+(?<Client>(\w+\.\w+\.\w+)|(\w+))?\s+(?<Dest_Media_Svr>(\w+\.\w+\.\w+)|(\w+))?\s+(?<Active_PID>\d+)?\s+(?<FATPipe>\b[^\d\W]+\b)?"
   $Results+=$matches
   }

以下是我编写的一小部分 Shell 代码(这显然是非常错误的,在这里边学习边学习)。我只是用它来测试正则表达式,看看它是否在 Shell 中起作用——(剧透警告)它没有。

#!/bin/bash
#

backups=bpdbjobs
results=()

for results in $backups; do

    [[ $results =~ /(?<jobID>\d+)?\s+(?<Type>(\b[^\d\W]+\b)|(\b[^\d\W]+\b\s+\b[^\d\W]+\b))?\s+(?<State>(Done)|(Active)|(\w+\w+\-\w\-+))?\s+(?<Status>\d+)?\s+(?<Policy>(\w+)|(\w+\_\w+)|(\w+\_\w+\_\w+))?\s+(?<Schedule>(\b[^\d\W]+\b\-\b[^\d\W]+\b)|(\-)|(\b[^\d\W]+\b))?\s+(?<Client>(\w+\.\w+\.\w+)|(\w+))?\s+(?<Dest_Media_Svr>(\w+\.\w+\.\w+)|(\w+))?\s+(?<Active_PID>\d+)?/ ]]

done

$results

以下是我得到的错误。

 ./netbackupsolarwinds.sh: line 9: syntax error in conditional expression: unexpected token `('
 ./netbackupsolarwinds.sh: line 9: syntax error near `/(?'
 ./netbackupsolarwinds.sh: line 9: `        [[ $results =~ /(?<jobID>\d+)?\s+(?<Type>(\b[^\d\W]+\b)|(\b[^\d\W]+\b\s+\b[^\d\W]+\b))?\s+(?<State>(Done)|(Active)|(\w+\w+\-\w\-+))?\s+(?<Status>\d+)?\s+(?<Policy>(\w+)|(\w+\_\w+)|(\w+\_\w+\_\w+))?\s+(?<Schedule>(\b[^\d\W]+\b\-\b[^\d\W]+\b)|(\-)|(\b[^\d\W]+\b))?\s+(?<Client>(\w+\.\w+\.\w+)|(\w+))?\s+(?<Dest_Media_Svr>(\w+\.\w+\.\w+)|(\w+))?\s+(?<Active_PID>\d+)?/ ]]'

【问题讨论】:

  • 您可能需要通过在其前面加上 \ 来转义某些特殊字符,例如 ( 或 ),因此如果我理解,它会知道通过将其写为 (Active) 来查找文本 (Active)你的正则表达式正确。
  • @JCJ Escaping ( 将其含义从起始组更改为文字 (。对我来说( 工作得很好。
  • @JCJ 正如 Socowi 所说,没有一个括号是字面的,它们都表示正则表达式中的组。
  • @Djxinator 这是一个有趣的问题。但是,你应该把它煮沸。删除所有不必要的东西。您只需向我们展示核心问题。一行powershell代码,一行bash代码,报错信息就够了。
  • 在 bash 中,将每一端的 / 替换为单引号 ' - 这不是 PCRE!

标签: regex bash shell powershell


【解决方案1】:

来自man bash

可以使用额外的二元运算符 =~,其优先级与 == 和 != 相同。使用时,运算符右侧的字符串被视为扩展正则表达式并进行相应匹配(如regex(3))。

表示表达式被解析为 POSIX 扩展正则表达式,AFAIK 不支持命名捕获组 ((?&lt;name&gt;...)) 或字符转义 (\d, \w, \s, ...) .

如果你想使用[[ $var =~ expr ]],你需要重写正则表达式。否则使用grep(支持PCRE):

grep -P '(?<jobID>\d+)?\s+...' <<<$results

【讨论】:

    【解决方案2】:

    在 cmets 交换后更新了答案。

    快速执行迁移的最佳方法是使用 Grep 的 --perl-regexp Perl 兼容性选项,就像另一个答案中最终建议的那样。

    如果你仍然想用纯 Bash 执行这个操作,你需要相应地重写正则表达式,遵循the documentation

    【讨论】:

    • 没有。转义括号会导致语法错误“unexpected token '
    • 即便如此,这有什么帮助?括号定义捕获组。转义它们会将它们变成文字括号,这显然不是 OP 想要匹配的(因为它们也没有在 PowerShell 正则表达式中转义)。此外,表达式开头和结尾的正斜杠没有任何关系。这是 bash,而不是 Perl。或sed。或者 awk。
    • “/”为真;然后我要求 OP 有数据样本来尝试匹配测试。但是我再次不同意括号 => 在我看来,只有 OUTER 括号定义了捕获组。在捕获组(外括号)中包含捕获组(内括号)是没有意义的。
    • 你错了。 (?&lt;name&gt;(foo)) 使用嵌套的未命名捕获组定义命名捕获组。我同意表达式中的过度分组没有多大意义,但这并没有改变这些表达式的工作方式。作为参考,将'bar' -match '(?&lt;foo&gt;(ba)r)'; $matches[1] 的输出与PowerShell 中的'bar' -match '(?&lt;foo&gt;bar)'; $matches[1]'bar' -match '(?&lt;foo&gt;\(ba\)r)'; $matches[1] 进行比较。
    • 你对命名的捕获组是正确的,因此我更新了我的答案。
    【解决方案3】:

    感谢大家的回答。我换成 Grep -P 无济于事,原来命名的捕获组是 Grep -P 的问题。

    我也无法找到使用 Grep 将捕获组匹配输出到单个变量的方法。

    这导致我改用 perl,如下所示,并更改了我的正则表达式。

    bpdbjobs | perl -lne 'print "$1" if /(\d+)?\s+((\b[^\d\W]+\b)|(\b[^\d\W]+\b\s+\b[^\d\W]+\b))?\s+((Done)|(Active)|(\w+\w+\-\w\-+))?\s+(\d+)?\s+((\w+)|(\w+\_\w+)|(\w+\_\w+\_\w+))?\s+((b[^\d\W]+\b\-\b[^\d\W]+\b)|(\-)|(\b[^\d\W]+\b))?\s+((\w+\.\w+\.\w+)|(\w+))?\s+((\w+\.\w+\.\w+)|(\w+))?\s+(\d+)?/g'

    $&lt;num&gt; 指的是捕获组号。我现在可以列出、显示和(重要部分)计算单个组中的匹配数,对应于每列中的数据。

    【讨论】:

    • grep -P(我的系统上的版本 2.27)应该能够很好地处理命名捕获组。为了匹配,就是这样。但是,它不会为您提供反向引用来提取子匹配。如果您想对捕获的组进行实际操作,则需要 sedawk(或 Perl 或课程)之类的东西。
    猜你喜欢
    • 2020-03-11
    • 2015-08-10
    • 1970-01-01
    • 1970-01-01
    • 2020-07-06
    • 2016-08-01
    • 2019-08-23
    • 2017-09-06
    • 1970-01-01
    相关资源
    最近更新 更多