如何在bash regex替换中引用捕获

时间:2011-04-11 17:15:24

标签: regex bash

如何在BASH中的替换表达式中包含正则表达式匹配?

非工作示例:

#!/bin/bash
name=joshua
echo ${name//[oa]/X\1}

我希望输出jXoshuXa并将\1替换为匹配的字符。

这实际上并不起作用,而是输出jX1shuX1

3 个答案:

答案 0 :(得分:26)

也许并不像所有地狱那样直观且可以说是模糊不清,但是在完整性的精神中,当我们等待替换BASH捕获到达时,目前可能存在以下情况。

#!/bin/bash
name='joshua'
[[ $name =~ ([ao].*)([oa]) ]] && \
    echo ${name/$BASH_REMATCH/X${BASH_REMATCH[1]}X${BASH_REMATCH[2]}}

在那个例子中,我们知道我们在寻找什么。更接近匹配所有或全局正则表达式对应物,以下示例将贪婪匹配到没有前缀X的集合的最后一次出现并继续向后直到没有剩余。

#/bin/bash
name='joshua'
while [[ $name =~ .*[^X]([oa]) ]]; do
    name=${name/$BASH_REMATCH/${BASH_REMATCH:0:-1}X${BASH_REMATCH[1]}}
done 
echo $name

该示例将类似于后面的表达式/(?<!X)([oa])/X\1/,它假设只关心o和没有X前缀的字符。

两个例子的输出

jXoshuXa

的nJoy!

答案 1 :(得分:8)

bash> name=joshua  
bash> echo $name | sed 's/\([oa]\)/X\1/g'  
jXoshuXa

答案 2 :(得分:0)

尽管有以下要求,问题bash string substitution: reference matched subexpressions被标记为与该问题重复的内容

  

代码在长循环中运行,它应该是单线的,不会   启动子流程。

所以答案是:

如果您真的负担不起在子进程中启动sed,请不要使用bash!,而是使用perl,其read-update-output循环将快几倍,并且语法差异很小。 (好吧,您一定不要忘记分号。)

我切换到perl,只有一个陷阱:一台计算机上没有Unicode支持,我不得不重新安装软件包。