我想从字符串中删除前缀/后缀。例如,给定:

string="hello-world"
prefix="hell"
suffix="ld"

如何得到以下结果?

"o-wor"

当前回答

注:不确定这在2013年是否可能,但今天(2021年10月10日)肯定是可能的,所以增加了另一个选项…


由于我们处理的是已知的固定长度字符串(前缀和后缀),因此可以使用bash子字符串通过单个操作获得所需的结果。

输入:

string="hello-world"
prefix="hell"
suffix="ld"

计划:

Bash子字符串语法:${字符串:<开始>:<长度>} 跳过prefix="hell"意味着我们的<start>将是4 <length>将是字符串的总长度(${#string})减去固定长度的字符串长度(hell为4 / ld为2)

这给了我们:

$ echo "${string:4:(${#string}-4-2)}"
o-wor

注意:可以删除paren,仍然得到相同的结果


如果prefix和suffix的值未知,或者可能会变化,我们仍然可以使用相同的操作,但将4和2分别替换为${#prefix}和${#suffix}:

$ echo "${string:${#prefix}:${#string}-${#prefix}-${#suffix}}"
o-wor

其他回答

你知道你的前缀和后缀的长度吗?在你的情况下:

result=$(echo $string | cut -c5- | rev | cut -c3- | rev)

或者更一般地说:

result=$(echo $string | cut -c$((${#prefix}+1))- | rev | cut -c$((${#suffix}+1))- | rev)

但是Adrian Frühwirth的解决方案非常酷!我不知道!

使用sed:

$ echo "$string" | sed -e "s/^$prefix//" -e "s/$suffix$//"
o-wor

在sed命令中,^字符匹配以$前缀开头的文本,后面的$匹配以$后缀结尾的文本。

Adrian Frühwirth在下面的评论中提出了一些很好的观点,但是sed对于这个目的非常有用。sed可以解释$prefix和$suffix的内容,这一事实可能是好的,也可能是坏的——只要您注意,就不会有问题。美妙之处在于,你可以这样做:

$ prefix='^.*ll'
$ suffix='ld$'
$ echo "$string" | sed -e "s/^$prefix//" -e "s/$suffix$//"
o-wor

这可能是您想要的,而且比bash变量替换更漂亮、更强大。如果你记得能力越大责任越大(正如蜘蛛侠所说),你就会没事。

可以在http://evc-cit.info/cit052/sed_tutorial.html上找到sed的快速介绍

关于shell及其字符串使用的注意事项:

对于给定的特定示例,下面的代码也可以使用:

$ echo $string | sed -e s/^$prefix// -e s/$suffix$//

...但这只是因为:

Echo并不关心参数列表中有多少字符串 $前缀和$后缀中没有空格

在命令行上引用字符串通常是一种良好的实践,因为即使它包含空格,它也将作为单个参数显示给命令。我们引用$prefix和$suffix是出于同样的原因:将每个编辑命令作为一个字符串传递给sed。我们使用双引号是因为它们允许变量内插;如果我们使用单引号,sed命令将得到一个字面的$前缀和$后缀,这当然不是我们想要的。

还要注意,我在设置变量前缀和后缀时使用了单引号。我们当然不希望字符串中的任何内容被解释,所以我们对它们进行单引号,这样就不会发生插值。同样,在这个例子中可能没有必要,但这是一个很好的习惯。

小而通用的解决方案:

expr "$string" : "$prefix\(.*\)$suffix"
$ prefix="hell"
$ suffix="ld"
$ string="hello-world"
$ foo=${string#"$prefix"}
$ foo=${foo%"$suffix"}
$ echo "${foo}"
o-wor

这在手册的Shell参数扩展部分中有记录:

${parameter#word} ${parameter##word} The word is expanded to produce a pattern and matched according to the rules described below (see Pattern Matching). If the pattern matches the beginning of the expanded value of parameter, then the result of the expansion is the expanded value of parameter with the shortest matching pattern (the # case) or the longest matching pattern (the ## case) deleted. […] ${parameter%word} ${parameter%%word} The word is expanded to produce a pattern and matched according to the rules described below (see Pattern Matching). If the pattern matches a trailing portion of the expanded value of parameter, then the result of the expansion is the value of parameter with the shortest matching pattern (the % case) or the longest matching pattern (the %% case) deleted. […]

$ string="hello-world"
$ prefix="hell"
$ suffix="ld"

$ #remove "hell" from "hello-world" if "hell" is found at the beginning.
$ prefix_removed_string=${string/#$prefix}

$ #remove "ld" from "o-world" if "ld" is found at the end.
$ suffix_removed_String=${prefix_removed_string/%$suffix}
$ echo $suffix_removed_String
o-wor

注:

#$prefix:添加#确保子字符串“hell”只在开头被发现时才被删除。 %$后缀:添加%确保子字符串“ld”只有在end中找到时才会被删除。

如果没有这些,子字符串“hell”和“ld”将被删除,即使它是在中间找到的。