639

在我的bash脚本中,我有一个字符串及其前缀/后缀。我需要从原始字符串中删除前缀/后缀。

例如,假设我有以下值:

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

我如何得到以下结果?

result="o-wor"
4

10 回答 10

968
$ foo=${string#"$prefix"}
$ foo=${foo%"$suffix"}
$ echo "${foo}"
o-wor

这记录在手册的Shell Parameter Expansion部分:

${parameter#word}
${parameter##word}

该词被扩展以产生一个模式并根据下面描述的规则进行匹配(请参阅模式匹配)。如果模式匹配参数扩展值的开头,则扩展的结果是删除了最短匹配模式(#案例)或最长匹配模式(案例)的参数扩展值。##[…]

${parameter%word}
${parameter%%word}

该词被扩展以产生一个模式并根据下面描述的规则进行匹配(请参阅模式匹配)。如果模式匹配参数扩展值的尾随部分,则扩展的结果是删除了最短匹配模式(%案例)或最长匹配模式(案例)的参数值。%%[…]

于 2013-05-18T11:43:59.300 回答
127

Using sed:

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

Within the sed command, the ^ character matches text beginning with $prefix, and the trailing $ matches text ending with $suffix.

Adrian Frühwirth makes some good points in the comments below, but sed for this purpose can be very useful. The fact that the contents of $prefix and $suffix are interpreted by sed can be either good OR bad- as long as you pay attention, you should be fine. The beauty is, you can do something like this:

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

which may be what you want, and is both fancier and more powerful than bash variable substitution. If you remember that with great power comes great responsibility (as Spiderman says), you should be fine.

A quick introduction to sed can be found at http://evc-cit.info/cit052/sed_tutorial.html

A note regarding the shell and its use of strings:

For the particular example given, the following would work as well:

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

...but only because:

  1. echo doesn't care how many strings are in its argument list, and
  2. There are no spaces in $prefix and $suffix

It's generally good practice to quote a string on the command line because even if it contains spaces it will be presented to the command as a single argument. We quote $prefix and $suffix for the same reason: each edit command to sed will be passed as one string. We use double quotes because they allow for variable interpolation; had we used single quotes the sed command would have gotten a literal $prefix and $suffix which is certainly not what we wanted.

Notice, too, my use of single quotes when setting the variables prefix and suffix. We certainly don't want anything in the strings to be interpreted, so we single quote them so no interpolation takes place. Again, it may not be necessary in this example but it's a very good habit to get into.

于 2014-05-17T19:38:23.800 回答
21

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

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 的解决方案非常酷!我不知道!

于 2017-01-16T20:09:08.663 回答
20
$ 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”只有在开始时才被删除。%$suffix :添加 % 确保子字符串“ld”只有在最后找到时才会被删除。

没有这些,子字符串“hell”和“ld”将被到处删除,即使它在中间被发现。

于 2018-09-08T08:47:13.607 回答
19

我使用 grep 从路径中删除前缀(这不是很好处理的sed):

echo "$input" | grep -oP "^$prefix\K.*"

\K从匹配中删除它之前的所有字符。

于 2016-09-16T11:28:43.617 回答
8

使用=~运算符

$ string="hello-world"
$ prefix="hell"
$ suffix="ld"
$ [[ "$string" =~ ^$prefix(.*)$suffix$ ]] && echo "${BASH_REMATCH[1]}"
o-wor
于 2018-01-12T05:14:43.383 回答
7

小而通用的解决方案:

expr "$string" : "$prefix\(.*\)$suffix"
于 2017-07-08T23:34:28.617 回答
6

使用@Adrian Frühwirth 回答:

function strip {
    local STRING=${1#$"$2"}
    echo ${STRING%$"$2"}
}

像这样使用它

HELLO=":hello:"
HELLO=$(strip "$HELLO" ":")
echo $HELLO # hello
于 2017-02-08T06:47:59.820 回答
2

注意:不确定这在 2013 年是否可行,但今天(2021 年 10 月 10 日)肯定可行,因此添加另一个选项...


由于我们正在处理已知的固定长度字符串 (prefixsuffix),我们可以使用bash子字符串通过单个操作获得所需的结果。

输入:

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

计划:

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

这给了我们:

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

注意:可以删除括号并仍然获得相同的结果


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

$ echo "${string:${#prefix}:${#string}-${#prefix}-${#suffix}}"
o-wor
于 2021-10-10T13:56:56.797 回答
0

我会在正则表达式中使用捕获组:

$ string="hello-world"
$ prefix="hell"
$ suffix="ld"
$ set +H # Disables history substitution, can be omitted in scripts.
$ perl -pe "s/${prefix}((?:(?!(${suffix})).)*)${suffix}/\1/" <<< $string
o-wor
$ string1=$string$string
$ perl -pe "s/${prefix}((?:(?!(${suffix})).)*)${suffix}/\1/g" <<< $string1
o-woro-wor

((?:(?!(${suffix})).)*)确保 的内容${suffix}将从捕获组中排除。就示例而言,它是等价于[^A-Z]*. 否则你会得到:

$ perl -pe "s/${prefix}(.*)${suffix}/\1/g" <<< $string1
o-worldhello-wor
于 2019-10-02T09:26:41.887 回答