在shell脚本中替换另一个字符串的子字符串

时间:2012-11-03 16:01:23

标签: bash shell

我有“我爱Suzi和Marry”,我想把“Suzi”改为“Sara”。

#!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
# do something...

结果必须如下:

firstString="I love Sara and Marry"

10 个答案:

答案 0 :(得分:982)

要使用给定字符串替换模式的第一个出现,请使用${parameter/pattern/string}

#!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
echo "${firstString/Suzi/$secondString}"    
# prints 'I love Sara and Marry'

要替换所有次出现,请使用${parameter//pattern/string}

message='The secret code is 12345'
echo "${message//[0-9]/X}"           
# prints 'The secret code is XXXXX'

(这在the Bash Reference Manual, §3.5.3 "Shell Parameter Expansion"中有记录。)

请注意,POSIX没有指定此功能 - 它是Bash扩展 - 因此并非所有Unix shell都实现它。有关POSIX文档,请参阅The Open Group Technical Standard Base Specifications, Issue 7, the Shell & Utilities volume, §2.6.2 "Parameter Expansion"

答案 1 :(得分:158)

这可以完全用bash字符串操作完成:

first="I love Suzy and Mary"
second="Sara"
first=${first/Suzy/$second}

这将只取代第一次出现;要替换它们,将第一个斜线加倍:

first="Suzy, Suzy, Suzy"
second="Sara"
first=${first//Suzy/$second}
# first is now "Sara, Sara, Sara"

答案 2 :(得分:57)

试试这个:

 sed "s/Suzi/$secondString/g" <<<"$firstString"

答案 3 :(得分:43)

如果字符串具有RegExp字符,则使用bash比使用sed更好。

echo ${first_string/Suzi/$second_string}

它可移植到Windows,并且至少与Bash 3.1一样老。

为了表明你不必担心逃避让我们转过身来:

/home/name/foo/bar

进入这个:

~/foo/bar

但只有在/home/name开头时才会这样。我们不需要sed

鉴于bash为我们提供了神奇变量$PWD$HOME,我们可以:

echo "${PWD/#$HOME/\~}"

编辑:感谢Mark Haferkamp在关于引用/转义~的说明中的评论。*

请注意变量$HOME如何包含斜杠,但这并没有破坏任何内容。

进一步阅读:Advanced Bash-Scripting Guide
如果必须使用sed,请务必escape every character

答案 4 :(得分:42)

对于Dash,所有以前的帖子都无效

POSIX sh兼容解决方案是:

result=$(echo "$firstString" | sed "s/Suzi/$secondString/")

答案 5 :(得分:15)

如果明天你决定不爱结婚,她也可以被替换:

today=$(</tmp/lovers.txt)
tomorrow="${today//Suzi/Sara}"
echo "${tomorrow//Marry/Jesica}" > /tmp/lovers.txt

离开你的情人必须有50种方法。

答案 6 :(得分:11)

echo [string] | sed "s/[original]/[target]/g"
  • “ s”表示“替代”
  • “ g”表示“所有匹配的全局变量”

答案 7 :(得分:2)

由于我无法添加评论。 @ruaka为了使示例更具可读性,请像这样编写它

full_string="I love Suzy and Mary"
search_string="Suzy"
replace_string="Sara"
my_string=${full_string/$search_string/$replace_string}
or
my_string=${full_string/Suzy/Sarah}

答案 8 :(得分:1)

POSIX shell方法,它与Roman Kazanovskyi's sed-based answer不同,它不需要外部工具,而仅是shell自己的本机parameter expansions。请注意,将长文件名最小化,因此代码更适合一行:

f="I love Suzi and Marry"
s=Sara
t=Suzi
[ "${f%$t*}" != "$f" ] && f="${f%$t*}$s${f#*$t}"
echo "$f"

输出:

I love Sara and Marry

工作原理:

  • 删除最小后缀模式。如果后缀"${f%$t*}" I love ”位于$t中,则Suzi*返回“ $f I love Suzi and Marry ”。

  • 但是如果t=Zelda,则"${f%$t*}"不会删除任何内容,并返回整个字符串“ I love Suzi and Marry ”。

  • 这用于测试$t是否在$f[ "${f%$t*}" != "$f" ]中,如果$f字符串将得出 true 包含“ Suzi* ”,如果没有则包含 false

  • 如果测试返回 true ,请使用删除最小后缀模式 ${f%$t*} I love < / em>”和删除最小前缀模式 ${f#*$t} and Marry ”,并使用 2nd 字符串{{1 }}之间的“ $s ”。

答案 9 :(得分:1)

我知道这已经很老了,但是由于没有人提到使用awk:

vpshufb ymm0, ymm0, ymmword ptr ds:[0x100]