bash 子字符串替换可以使用正则表达式吗?

Can bash substring replacement use regexs?

给定一个字符串,例如

string="val1 val2 val3 val4"

如何使用 bash 子字符串替换来删除给定的子字符串及其相邻的 space(可能存在也可能不存在)?

例如,这会导致额外的 spaces:

val='val2'
string=${string/$val/}
# string = "val1  val3 val4"

在我的实际代码中,我不会预先知道子字符串是什么或它在字符串中的位置,因此不知道它是否具有前导或尾随 space。我想做这样的事情,就像你在 sed 中做的那样,但当然没有成功:

val=" *val2 *"
string=${string/$val/ }
# In my fictitious universe, string = "val1 val3 val4"
# In the real world, string = "val1"

sed 中,我会使用 sed -e 's/ *val2 */ /' 之类的东西,但我想在 bash.

中完成所有这些操作

有没有办法定义子字符串,使模式包含零个或多个 spaces + 'val2' + 零个或多个 spaces?

提供 extglob shell 选项已启用,

$ string="val1 val2 val3 val4"
$ v=val2
$ echo "${string/*( )$v*( )/ }"
val1 val3 val4
  • string/ 用于搜索和替换第一次出现的模式。使用 string// 替换所有匹配项。请参阅 Parameter Expansion 以进一步阅读
  • *( ) 表示零个或多个 space。有关 extglob 选项
  • 的更多详细信息和使用,请参阅 Pattern Matching manual
  • 替换模式是单个space个字符

规范问题

视为初始状态:

v=val2
string="val1 val21 val2 val3 val4"

实施此问题要求的精确行为将导致:

string="val1 1 val3 val4"

...或者,也许:

string="val1 1 val2 val3 val4"

我在下面假设在这种情况下你真正想要的输出是:

string="val1 val21 val3 val4"

方法:Posix扩展正则表达式/BASH_REMATCH

这比绝对必要的要复杂得多(对于手头的直接情况,我会使用下面显示的替代方法),但显示了在本机中使用正则表达式替换字符串 bash -- 这通常是一种有用的技术。

考虑使用 [[ $string =~ $re ]],它使用正则表达式 re:

中的任何组填充数组 BASH_REMATCH
string="val1 val2 val3 val4"
val=val2

if [[ $string =~ (.*(^|[[:space:]]))"$val"(($|[[:space:]]).*) ]]; then
  string="${BASH_REMATCH[1]}${BASH_REMATCH[3]}"
  string=${string//  / } # deal with any places where spaces are doubled up
fi

用临时填充替换模式

无条件地在您的字符串前面加上空格意味着您可以使用相同的替换逻辑,没有类似正则表达式的条件,您的值位于字符串的任何位置:

string="val1 val2 val3 val4"
val=val2

s=" $string "       # Unconditionally add leading and trailing spaces
s=${s// $val / }    # Substitute the value only when surrounded by space
s=${s# }; s=${s% }  # Trim leading and trailing spaces back off

string=$s