从Bash中的字符串中删除固定的前缀/后缀

Duš*_*ský 437 bash

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

例如,假设我有以下值:

string="hello-world"
prefix="hell"
suffix="ld"
Run Code Online (Sandbox Code Playgroud)

我如何得到以下结果?

result="o-wor"
Run Code Online (Sandbox Code Playgroud)

Adr*_*rth 641

$ foo=${string#"$prefix"}
$ foo=${foo%"$suffix"}
$ echo "${foo}"
o-wor
Run Code Online (Sandbox Code Playgroud)

  • @AdrianFrühwirth:整个语言都很遗憾,但它非常有用:) (76认同)
  • 还有##和%%,如果$ prefix或$ suffix包含通配符,它​​们会尽可能地删除. (38认同)
  • @static_rtti不,遗憾的是你不能像这样嵌套参数替换.我知道,这很遗憾. (20认同)
  • 有没有办法将两者合二为一?我试过`$ {$ {string #prefix}%suffix}`但它不起作用. (17认同)
  • Nvm,Google中的"bash替代"找到了我想要的东西. (8认同)
  • 有什么东西叫,我在哪里可以找到它们的参考? (3认同)
  • 这在Advanced Bash-Scripting Guide的参数替换部分中有记录:http://www.tldp.org/LDP/abs/html/parameter-substitution.html. (3认同)
  • @static_rtti,有一个解决方法:echo`basename $ {string/hell} ld`(灰色部分在反引号之间) (2认同)
  • @ccpizza参数替换不知道这样的修饰符,但如果它是一个固定的字符串,你总是可以做例如`$ {foo#[Bb] [Aa] [Rr]}`.不是很漂亮,但仍然可能比不必要的子shell/fork更好,具体取决于具体情况. (2认同)
  • 请注意,魔术字符是`#`和`%`,而不是`#$`和`%$`-在上面的示例中,`$`是$ prefix`的一部分-乍一看可能不清楚 (2认同)

Chr*_*din 80

使用sed:

$ echo "$string" | sed -e "s/^$prefix//" -e "s/$suffix$//"
o-wor
Run Code Online (Sandbox Code Playgroud)

在sed命令中,^字符匹配以?开头的文本$prefix,尾随$匹配以$suffix.结尾的文本.

AdrianFrühwirth在下面的评论中提出了一些好处,但sed为此目的可能非常有用.$ sed和$ suffix的内容由sed解释的事实可能是好的或坏的 - 只要你注意,你应该没事.美丽的是,你可以这样做:

$ prefix='^.*ll'
$ suffix='ld$'
$ echo "$string" | sed -e "s/^$prefix//" -e "s/$suffix$//"
o-wor
Run Code Online (Sandbox Code Playgroud)

这可能是你想要的,并且比bash变量替换更有魅力和更强大.如果你记得有很大的力量就会有很大的责任(正如蜘蛛侠说的那样),你应该没事.

有关sed的快速介绍,请访问http://evc-cit.info/cit052/sed_tutorial.html

关于shell及其字符串使用的注释:

对于给出的特定示例,以下内容也可以使用:

$ echo $string | sed -e s/^$prefix// -e s/$suffix$//
Run Code Online (Sandbox Code Playgroud)

......但仅仅是因为:

  1. echo不关心它的参数列表中有多少个字符串,以及
  2. $ prefix和$ suffix中没有空格

在命令行上引用字符串通常是一种好习惯,因为即使它包含空格,它也会作为单个参数显示给命令.我们引用$ prefix和$ suffix的原因相同:sed的每个edit命令都将作为一个字符串传递.我们使用双引号,因为它们允许变量插值; 如果我们使用单引号,sed命令会得到一个字面值$prefix,$suffix这肯定不是我们想要的.

还请注意,我设置的变量时,使用单引号prefixsuffix.我们当然不希望对字符串中的任何内容进行解释,因此我们单引引它们以便不进行插值.同样,在这个例子中可能没有必要,但这是一个非常好的习惯.

  • 不幸的是,由于以下几个原因,这是一个糟糕的建议:1)不带引号,`$ string`受到单词拆分和通配.2)`$ prefix`和`$ suffix`可以包含`sed`将解释的表达式,例如正则表达式或用作分隔符的字符,它将破坏整个命令.3)不需要两次调用`sed`(你可以`-e'S'/'-e'///'`而且管道也可以避免.例如,考虑`string ='./*'`和/或`prefix ='./'`并看到它由于`1)`和`2)`而可怕地破坏. (7认同)
  • @Olie:据我理解您最初的评论,您是说您选择使用“#”作为 sed 分隔符的限制意味着您无法处理包含该字符的文件。 (3认同)

tom*_*sen 15

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

result=$(echo $string | cut -c5- | rev | cut -c3- | rev)
Run Code Online (Sandbox Code Playgroud)

或者更一般:

result=$(echo $string | cut -c$((${#prefix}+1))- | rev | cut -c$((${#suffix}+1))- | rev)
Run Code Online (Sandbox Code Playgroud)

AdrianFrühwirth解决方案很酷!我不知道那个!


Vla*_*ich 14

我使用grep从路径中删除前缀(没有很好地处理sed):

echo "$input" | grep -oP "^$prefix\K.*"
Run Code Online (Sandbox Code Playgroud)

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

  • 不,例如 MacOS 有开箱即用的 Bash,但没有 GNU `grep`。早期版本实际上有来自 BSD `grep` 的 `-P` 选项,但他们删除了它。 (3认同)
  • `grep -P` 是一个非标准的扩展。如果你的平台支持它,它会给你更多的力量,但如果你的代码需要合理的可移植性,这是一个可疑的建议。 (2认同)

Vij*_*Vat 8

$ 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
Run Code Online (Sandbox Code Playgroud)

笔记:

#$ prefix:添加#确保仅在开头找到子字符串“ hell”。%$ suffix:添加%可以确保仅在结尾找到子字符串“ ld”。

没有这些,子字符串“ hell”和“ ld”将在所有位置删除,即使在中间也可以找到。


mar*_*rkp 8

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


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

输入:

string="hello-world"
prefix="hell"
suffix="ld"
Run Code Online (Sandbox Code Playgroud)

计划:

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

这给了我们:

$ echo "${string:4:(${#string}-4-2)}"
o-wor
Run Code Online (Sandbox Code Playgroud)

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


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

$ echo "${string:${#prefix}:${#string}-${#prefix}-${#suffix}}"
o-wor
Run Code Online (Sandbox Code Playgroud)


小智 6

小而通用的解决方案:

expr "$string" : "$prefix\(.*\)$suffix"
Run Code Online (Sandbox Code Playgroud)


Mar*_*ーチン 6

使用=~运算符

$ string="hello-world"
$ prefix="hell"
$ suffix="ld"
$ [[ "$string" =~ ^$prefix(.*)$suffix$ ]] && echo "${BASH_REMATCH[1]}"
o-wor
Run Code Online (Sandbox Code Playgroud)


mat*_*001 5

使用@AdrianFrühwirth答案:

function strip {
    local STRING=${1#$"$2"}
    echo ${STRING%$"$2"}
}
Run Code Online (Sandbox Code Playgroud)

这样使用

HELLO=":hello:"
HELLO=$(strip "$HELLO" ":")
echo $HELLO # hello
Run Code Online (Sandbox Code Playgroud)