在我的 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} 单词被扩展以产生一个模式并根据下面描述的规则进行匹配(参见模式匹配)。如果模式匹配参数扩展值的开头,则扩展结果是删除了最短匹配模式(#case)或最长匹配模式(##case)的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$//
...但仅仅是因为:
echo 不关心它的参数列表中有多少个字符串,并且 $prefix 和 $suffix 中没有空格
在命令行上引用字符串通常是一种很好的做法,因为即使它包含空格,它也会作为单个参数呈现给命令。出于同样的原因,我们引用 $prefix 和 $suffix:每个 sed 的编辑命令都将作为一个字符串传递。我们使用双引号是因为它们允许变量插值;如果我们使用单引号,sed 命令会得到一个字面值 $prefix
和 $suffix
,这肯定不是我们想要的。
请注意,我在设置变量 prefix
和 suffix
时使用了单引号。我们当然不希望字符串中的任何内容被解释,所以我们将它们单引号,这样就不会发生插值。同样,在此示例中可能没有必要,但这是一个非常好的习惯。
$string
会受到分词和通配符的影响。 2) $prefix
和 $suffix
可以包含 sed
将解释的表达式,例如正则表达式或用作分隔符的字符会破坏整个命令。 3) 不需要调用 sed
两次(你可以用 -e 's///' -e '///'
代替),也可以避免管道。例如,考虑 string='./ *'
和/或 prefix='./'
并看到它由于 1)
和 2)
而严重损坏。
/
,所以我使用了 sed "s#^$prefix##
。 (脆弱性:文件名不能包含 #
。因为我控制了文件,所以我们在那里很安全。)
#
作为 sed 的分隔符的限制意味着您无法处理包含该字符的文件。
$ 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)
但是 solution from Adrian Frühwirth 太酷了!我不知道!
我使用 grep 从路径中删除前缀(sed
处理不好):
echo "$input" | grep -oP "^$prefix\K.*"
\K
从匹配中删除它之前的所有字符。
grep -P
是非标准扩展。如果您的平台支持它,则为您提供更多功能,但如果您的代码需要合理可移植,这是一个可疑的建议。
grep
。早期版本实际上有来自 BSD grep
的 -P
选项,但他们删除了它。
使用 =~
operator:
$ string="hello-world"
$ prefix="hell"
$ suffix="ld"
$ [[ "$string" =~ ^$prefix(.*)$suffix$ ]] && echo "${BASH_REMATCH[1]}"
o-wor
小而通用的解决方案:
expr "$string" : "$prefix\(.*\)$suffix"
expr
。在最初的 Bourne shell 时代,它是一种某种方便的厨房水槽实用工具,但现在已经过了最佳使用日期。
expr
已旧,但从未更改,并且可能始终可用。只要您调用外部二进制文件(而不是使用 BASH 表达式),grep、sed 或 expr 就几乎是等价的(perl / awk 会更昂贵)。
使用@Adrian Frühwirth 回答:
function strip {
local STRING=${1#$"$2"}
echo ${STRING%$"$2"}
}
像这样使用它
HELLO=":hello:"
HELLO=$(strip "$HELLO" ":")
echo $HELLO # hello
注意:不确定这在 2013 年是否可行,但今天(2021 年 10 月 10 日)肯定可行,因此添加另一个选项...
由于我们正在处理已知的固定长度字符串(prefix
和 suffix
),我们可以使用 bash
子字符串通过单个操作获得所需的结果。
输入:
string="hello-world"
prefix="hell"
suffix="ld"
计划:
bash 子字符串语法:${string:
跳过 prefix="hell" 意味着我们的
这给了我们:
$ echo "${string:4:(${#string}-4-2)}"
o-wor
注意:可以删除括号并仍然获得相同的结果
如果 prefix
和 suffix
的值未知或可能不同,我们仍然可以使用相同的操作,但将 4
和 2
分别替换为 ${#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}
的内容将从捕获组中排除。例如,它是相当于 [^A-Z]*
的字符串。否则你会得到:
$ perl -pe "s/${prefix}(.*)${suffix}/\1/g" <<< $string1
o-worldhello-wor
不定期副业成功案例分享
${${string#prefix}%suffix}
,但它不起作用。basename ${string/hell} ld
(灰色部分在反引号之间)