繁体   English   中英

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

[英]Remove a fixed prefix/suffix from a string in Bash

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

例如,假设我有以下值:

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

我如何得到以下结果?

result="o-wor"
$ prefix="hell"
$ suffix="ld"
$ string="hello-world"
$ foo=${string#"$prefix"}
$ foo=${foo%"$suffix"}
$ echo "${foo}"
o-wor

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

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

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

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

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

使用 sed:

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

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

Adrian Frühwirth 在下面的评论中提出了一些好的观点,但为此目的sed可能非常有用。 $prefix 和 $suffix 的内容被 sed 解释的事实可能好也可能不好 - 只要你注意,你应该没问题。 美妙之处在于,您可以执行以下操作:

$ 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$//

...但仅仅是因为:

  1. echo 不在乎它的参数列表中有多少个字符串,并且
  2. $prefix 和 $suffix 中没有空格

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

请注意,我在设置变量prefixsuffix时使用了单引号。 我们当然不希望字符串中的任何内容被解释,所以我们将它们单引号,这样就不会发生插值。 同样,在此示例中可能没有必要,但这是一个非常好的习惯。

$ 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”将被到处删除,即使它在中间被发现。

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

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

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

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

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

使用=~运算符

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

小而通用的解决方案:

expr "$string" : "$prefix\(.*\)$suffix"

使用@Adrian Frühwirth 回答:

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

像这样使用它

HELLO=":hello:"
HELLO=$(strip "$HELLO" ":")
echo $HELLO # hello

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


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

输入:

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

计划:

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

这给了我们:

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

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


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

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

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

$ 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}的内容将从捕获组中排除。 例如,它相当于[^AZ]*的字符串。 否则你会得到:

$ perl -pe "s/${prefix}(.*)${suffix}/\1/g" <<< $string1
o-worldhello-wor

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM