BASH_REMATCH 空

Ale*_*lea 5 regex bash shell trepan

我正在尝试捕获 Bash 中的一些输入正则表达式,但 BASH_REMATCH 为空

#!/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"
Run Code Online (Sandbox Code Playgroud)

我的输入是:

    MailAccountFetch                         2017-03-29 19:00:00  Success      5.0 Second(s)      2017-03-29 19:03:00
Run Code Online (Sandbox Code Playgroud)

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

我上线了:

GNU bash, version 4.4.0(1)-release (x86_64-pc-linux-gnu)
Run Code Online (Sandbox Code Playgroud)

可能是什么问题?

稍后编辑


接受的答案

接受最具解释性的答案。

最终解决了这个问题:

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

mkl*_*nt0 5

正如 Cyrus 在他的回答中所示,代码的简化版本(具有相同的输入)原则上确实可以在 Linux 上运行。

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

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

但请注意,如果=~信号成功,BASH_REMATCH则永远不会完全为空:至少 - 在没有任何捕获组的情况下 -${BASH_REMATCH[0]}将被定义。


有一些一般性的观点值得一提:

  • 你的shebang 行#!/usr/bin/env /bin/bash这样的,实际上与 相同#!/bin/bash

    • /usr/bin/env如果您想要执行以外的版本(/bin/bash稍后安装并放入 PATH 中),通常会使用:
      #!/usr/bin/env bash

    • ghoti指出使用的另一个原因#!/usr/bin/env bash是还支持不太常见的平台,例如 FreeBSD,bash如果安装了,则位于/usr/local/bin而不是通常的/bin.

    • 在任何一种情况下,都很难预测bash将执行哪个二进制文件,因为它取决于$PATH调用时的有效值。

  • =~是少数依赖于平台的Bash 功能之一:它使用由平台的正则表达式库实现的特定正则表达式方言。

    • \s是一个字符类快捷方式,并非在所有平台上都可用,尤其是在 macOS 上;符合 POSIX 标准的等效项.[[:space:]]

    • (但是,在您的特定情况下,\s应该可以工作,因为您的 Bash--version输出表明您使用的是 Linux 发行版。)

  • 最好不要使用诸如 等全大写的 shell 变量名INPUT,以免与环境变量和特殊 shell 变量发生冲突