Bash正则表达式失效:在线编辑器可用但脚本内无法运行
解决Bash脚本中负向预查正则不工作的问题
我明白你的困扰——在线正则编辑器(通常支持PCRE Perl兼容正则)里能正常跑的规则,放到Bash里就失效了,这其实是因为Bash的[[ ... =~ ... ]]使用的是POSIX扩展正则表达式(ERE),不支持Perl风格的零宽断言(比如(?<!...)这种反向否定预查)。
先拆解你原来脚本的问题:
- 第一个
if里的正则完全写错了,你错误地转义了(?<!NOT.)成^(\?\<\!NOT\.),这既不符合POSIX规范,也不是正确的正则写法。 - 第二个
if里的$regex变量包含(?<!NOT.),但Bash不识别这种语法,所以匹配逻辑直接失效。
针对你的需求(匹配逗号分隔列表中未被NOT_前缀的TEST_34_TEST),这里有两个靠谱的解决方案:
方案1:用grep的PCRE模式(推荐处理复杂正则)
grep的-P参数支持Perl风格的正则,完美兼容你原来的正则表达式。可以用它来统计匹配数量或者判断是否存在匹配:
#!/bin/bash echo -n "Your string> " read String # 统计匹配到的TEST_34_TEST数量 match_count=$(grep -oP '(?<!NOT.)TEST_34_TEST' <<< "$String" | wc -l) echo "Matched $match_count instances of TEST_34_TEST" # 快速判断是否存在至少一个匹配 if grep -qP '(?<!NOT.)TEST_34_TEST' <<< "$String"; then echo "Match found" else echo "No matches" fi
grep -oP:-o输出每个匹配的独立结果,-P启用PCRE支持grep -qP:-q静默模式,只要有匹配就返回成功状态码,适合做条件判断
方案2:纯Bash实现(无外部依赖)
如果你的匹配规则比较简单(就是找纯TEST_34_TEST项,排除NOT_TEST_34_TEST),可以直接拆分逗号分隔的列表,逐个检查:
#!/bin/bash echo -n "Your string> " read String match_count=0 # 按逗号拆分字符串,同时处理项前后的空格 IFS=',' read -ra items <<< "$String" for item in "${items[@]}"; do # 去掉项前后的空格(兼容示例中的空格) trimmed=$(echo "$item" | xargs) # 直接判断是否是目标字符串 if [[ "$trimmed" == "TEST_34_TEST" ]]; then ((match_count++)) fi done echo "Matched $match_count times" (( match_count > 0 )) && echo "Match" || echo "Non-Match"
这个方案更直观,也不需要依赖外部工具,适合脚本需要轻量化的场景。
内容的提问来源于stack exchange,提问作者Ttj
相关产品推荐
相关产品推荐

