1

给定一个字符串,例如

string="val1 val2 val3 val4"

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

例如,这会导致额外的空格:

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

在我的实际代码中,我不会提前知道子字符串是什么或它在字符串中的位置,因此它是否有前导或尾随空格是未知的。我想做这样的事情,就像你在 中所做的那样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 中完成所有这些。

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

4

2 回答 2

4

规范问题

考虑作为初始状态:

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 中使用正则表达式进行字符串替换——这通常是一种有用的技术。

考虑使用,它使用regex 中的任何组[[ $string =~ $re ]]填充数组:BASH_REMATCHre

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
于 2016-08-17T02:09:07.483 回答
3

如果extglob启用了 shell 选项,

$ string="val1 val2 val3 val4"
$ v=val2
$ echo "${string/*( )$v*( )/ }"
val1 val3 val4
  • string/用于搜索和替换第一次出现的模式。用于string//替换所有匹配项。请参阅参数扩展以进一步阅读
  • *( )表示零个或多个空格。有关更多详细信息和选项的使用,请参阅模式匹配手册extglob
  • 替换模式是单个空格字符
于 2016-08-17T01:20:28.193 回答