BASH_REMATCH空
BASH_REMATCH empty
我正在尝试捕获 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),当代码进入 IF 时,我可以看到 INPUT 字符串匹配,但是 BASH_REMATCH 没有填充我的两个捕获组。
我在:
GNU bash, version 4.4.0(1)-release (x86_64-pc-linux-gnu)
可能是什么问题?
稍后编辑
已接受答案
接受最具解释性的回答。
最终解决问题的方法:
bashdb/VS 代码环境导致空 BASH_REMATCH。 单独 运行 时代码工作正常。
正如赛勒斯在他的回答中所展示的那样,您的代码的简化版本 - 使用相同的输入 - 原则上 Linux 。
就是说,您的代码引用了捕获组 3
和 4
,而您的正则表达式仅定义了 2.
换句话说:${BASH_REMATCH[3]}
和 ${BASH_REMATCH[4]}
根据定义为空。
但是请注意,如果 =~
表示成功,BASH_REMATCH
永远不会 完全 空:至少 - 在没有任何捕获的情况下组 - ${BASH_REMATCH[0]}
将被定义。
有一些一般性的观点值得提出:
您的 shebang 行 显示为 #!/usr/bin/env /bin/bash
,实际上与 #!/bin/bash
[=90= 相同].
/usr/bin/env
通常用于执行 other 而不是 /bin/bash
的版本,您稍后安装的版本和放入 PATH(也):
#!/usr/bin/env bash
ghoti 指出使用 #!/usr/bin/env bash
的另一个原因是还支持不太常见的平台,例如 FreeBSD,如果安装了 bash
,则位于在 /usr/local/bin
而不是通常的 /bin
.
在任何一种情况下,都很难预测将执行哪个 bash
二进制文件,因为它取决于调用时的有效 $PATH
值。
=~
是为数不多的 Bash 功能之一 平台相关:它使用由平台的正则表达式库实现的特定正则表达式方言。
\s
是字符 class 快捷方式,并非在所有平台上都可用,特别是在 macOS 上; POSIX 兼容的等价物是 [[:space:]]
.
(在您的特定情况下,\s
应该有效,但是,因为您的 Bash --version
输出表明您在 Linux发行版。)
最好不要使用全大写的shell变量名如INPUT
,这样avoid conflicts with environment variables and special shell variables.
Bash使用系统库解析正则表达式,不同的解析器实现不同的特性。您遇到了正则表达式 class shorthand 字符串不起作用的地方。请注意以下事项:
$ 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 快捷方式,您的表达方式将会得到更广泛的理解。
我正在尝试捕获 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),当代码进入 IF 时,我可以看到 INPUT 字符串匹配,但是 BASH_REMATCH 没有填充我的两个捕获组。
我在:
GNU bash, version 4.4.0(1)-release (x86_64-pc-linux-gnu)
可能是什么问题?
稍后编辑
已接受答案
接受最具解释性的回答。
最终解决问题的方法:
bashdb/VS 代码环境导致空 BASH_REMATCH。 单独 运行 时代码工作正常。
正如赛勒斯在他的回答中所展示的那样,您的代码的简化版本 - 使用相同的输入 - 原则上 Linux 。
就是说,您的代码引用了捕获组 3
和 4
,而您的正则表达式仅定义了 2.
换句话说:${BASH_REMATCH[3]}
和 ${BASH_REMATCH[4]}
根据定义为空。
但是请注意,如果 =~
表示成功,BASH_REMATCH
永远不会 完全 空:至少 - 在没有任何捕获的情况下组 - ${BASH_REMATCH[0]}
将被定义。
有一些一般性的观点值得提出:
您的 shebang 行 显示为
#!/usr/bin/env /bin/bash
,实际上与#!/bin/bash
[=90= 相同]./usr/bin/env
通常用于执行 other 而不是/bin/bash
的版本,您稍后安装的版本和放入 PATH(也):
#!/usr/bin/env bash
ghoti 指出使用
#!/usr/bin/env bash
的另一个原因是还支持不太常见的平台,例如 FreeBSD,如果安装了bash
,则位于在/usr/local/bin
而不是通常的/bin
.在任何一种情况下,都很难预测将执行哪个
bash
二进制文件,因为它取决于调用时的有效$PATH
值。
=~
是为数不多的 Bash 功能之一 平台相关:它使用由平台的正则表达式库实现的特定正则表达式方言。\s
是字符 class 快捷方式,并非在所有平台上都可用,特别是在 macOS 上; POSIX 兼容的等价物是[[:space:]]
.(在您的特定情况下,
\s
应该有效,但是,因为您的 Bash--version
输出表明您在 Linux发行版。)
最好不要使用全大写的shell变量名如
INPUT
,这样avoid conflicts with environment variables and special shell variables.
Bash使用系统库解析正则表达式,不同的解析器实现不同的特性。您遇到了正则表达式 class shorthand 字符串不起作用的地方。请注意以下事项:
$ 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 快捷方式,您的表达方式将会得到更广泛的理解。