如何用Bash脚本提取$...$分隔符间文本?现有代码无效
问题分析与解决方案
你的问题核心在于正则表达式的语法环境不匹配,以及对提取目标的处理偏差,我来拆解一下:
为什么原代码失效?
- 正则语法环境差异:
你在regex101测试的正则大概率用的是PCRE(Perl兼容正则)或ERE(扩展正则)模式,但bash默认的grep使用的是BRE(基础正则表达式)。在BRE中,()是字面字符(不是捕获组),所以你的正则\$([^\$]*)\$实际是在匹配$(xxx)$这种带括号的格式,但你的测试文本里根本没有括号,自然匹配不到。 - 提取目标偏差:
就算正则能匹配到,原代码会把包含$的整个串(比如$bfc2439c621353$)存入数组,而你需要的是去掉前后$的中间内容,这也不符合预期。
至于[0-9]\+能正常工作,是因为这个正则不需要捕获组,GNU grep的BRE模式也支持\+作为量词(多数Linux系统用的是GNU grep),所以能直接匹配到数字串。
修正方案
下面提供几种可行的解决方式,都能得到你想要的bfc2439c621353 629f结果:
方法1:使用PCRE模式的grep(推荐)
GNU grep支持-P参数启用PCRE模式,配合\K正向预查可以直接跳过前面的$,只提取中间内容:
#!/bin/bash array=($(grep -oP '\$\K[^\$]+' test.txt)) echo ${array[@]}
\$\K:匹配$后,丢弃该匹配结果,只保留后续的内容[^\$]+:匹配任意非$的字符(至少一个)
方法2:使用sed提取捕获组
sed适合处理文本替换,通过捕获组提取$之间的内容:
#!/bin/bash array=($(sed -n 's/.*\$\([^\$]*\)\$.*/\1/gp' test.txt)) echo ${array[@]}
-n:默认不输出行,只打印匹配替换后的内容s/.*\$\([^\$]*\)\$.*/\1/g:全局替换,把整行内容替换为$之间捕获到的部分p:打印替换后的结果
方法3:兼容基础正则的方案
如果你的系统不支持PCRE,也可以先用grep匹配整个$...$串,再用sed去掉前后的$:
#!/bin/bash array=($(grep -o '\$[^\$]*\$' test.txt | sed 's/^\$\(.*\)\$$/\1/')) echo ${array[@]}
- 第一步
grep -o '\$[^\$]*\$':匹配所有包含$的目标串 - 第二步
sed 's/^\$\(.*\)\$$/\1/':去掉每个串首尾的$
内容的提问来源于stack exchange,提问作者Glinka
相关产品推荐
相关产品推荐

