Bash - BASH_REMATCH为空

时间:2017-03-31 18:29:25

标签: regex bash shell

我尝试在Bash中捕获一些输入正则表达式,但是BASH_REMATCH来了EMPTY

#!/usr/bin/env /bin/bash
INPUT=$(cat input.txt)
TASK_NAME="MailAccountFetch"

MATCH_PATTERN="(${TASK_NAME})\s+([0-9]{4}-[0-9]{2}-[0-9]{2}\s[0-9]{2}:[0-9]{2}:[0-9]{2})"

while read -r line; do
    if [[ $line =~ $MATCH_PATTERN ]]; then
        TASK_RESULT=${BASH_REMATCH[3]}
        TASK_LAST_RUN=${BASH_REMATCH[2]}
        TASK_EXECUTION_DURATION=${BASH_REMATCH[4]}
    fi
done <<< "$INPUT"

我的意见是:

    MailAccountFetch                         2017-03-29 19:00:00  Success      5.0 Second(s)      2017-03-29 19:03:00

通过调试脚本(VS Code + Bash ext),我可以看到INPUT字符串匹配,因为代码进入IF内部,但BASH_REMATCH没有填充我的两个捕获组。

我在:

GNU bash, version 4.4.0(1)-release (x86_64-pc-linux-gnu)

可能是什么问题?

后期编辑

接受的答案

接受大多数解释性答案。

最终解决了这个问题:

bashdb / VS Code环境导致空BASH_REMATCH。 单独运行时代码正常。

2 个答案:

答案 0 :(得分:3)

正如Cyrus在他的回答中所说,代码的简化版本 - 具有相同的输入 - 在原则上适用于Linux

也就是说,您的代码引用了捕获组34,而您的正则表达式只定义了 2

换句话说:根据定义,${BASH_REMATCH[3]}${BASH_REMATCH[4]}为空。

但请注意,如果=~表示成功,BASH_REMATCH永远不会完全为空:至少 - 在没有任何捕获组的情况下 - {{1将被定义。

有一些值得一般的观点:

  • shebang line 读取${BASH_REMATCH[0]}#!/usr/bin/env /bin/bash 实际上相同。

    • #!/bin/bash通常用于执行其他而不是/usr/bin/env的版本,之后安装的版本并放入PATH(也是) :
      /bin/bash

    • ghoti指出使用#!/usr/bin/env bash的另一个原因是支持不太常见的平台,例如FreeBSD,其中#!/usr/bin/env bash(如果已安装)位于{{1}而不是通常的bash

    • 在任何一种情况下,执行/usr/local/bin二进制文件的可预测性较低,因为它取决于调用时的有效/bin值。

  • bash是为数不多的依赖于平台的 的Bash功能之一:它使用平台的正则表达式库实现的特定正则表达式方言

    • $PATH 并非在所有平台上都可用的字符类快捷方式,特别是不在macOS上;符合POSIX标准的 =~

    • (在您的特定情况下,\s应该有效,因为您的Bash [[:space:]]输出表明您使用的是Linux发行版。)

  • 最好不要使用全部大写的shell变量名,例如\s,以便avoid conflicts with environment variables and special shell variables

答案 1 :(得分:1)

Bash使用系统库来解析正则表达式,不同的解析器实现不同的功能。您遇到过正则表达式速记字符串不起作用的地方。请注意以下事项:

$ s="one12345   two"
$ [[ $s =~ ^([a-z]+[0-9]{4})\S*\s+(.*) ]] && echo yep; declare -p BASH_REMATCH
declare -ar BASH_REMATCH=()
$ [[ $s =~ ^([a-z]+[0-9]{4})[^[:space:]]*[[:space:]]+(.*) ]] && echo yep; declare -p BASH_REMATCH
yep
declare -ar BASH_REMATCH=([0]="one12345   two" [1]="one1234" [2]="two")

我也在macOS上这样做,但我在FreeBSD上也有同样的行为。

只需将\s替换为[[:space:]],将\d替换为[[:digit:]]等,您就应该好好去。如果您避免使用RE快捷键,您的表达式将被更广泛地理解。