我有“我爱 Suzi 和 Marry”,我想把“Suzi”改成“Sara”。
firstString="I love Suzi and Marry"
secondString="Sara"
期望的结果:
firstString="I love Sara and Marry"
要使用给定字符串替换模式的 first 出现,请使用 ${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"。
这可以完全通过 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"
first
或 second
包含特殊字符,例如 /
、$
、{
、}
、<反斜杠>、.
、+
、(
、)
,该怎么办? ,*
等? (此评论中反斜杠格式的问题。)也许在答案中解决这个问题?
对于 Dash,以前的所有帖子都不起作用
POSIX sh
兼容的解决方案是:
result=$(echo "$firstString" | sed "s/Suzi/$secondString/")
这将替换每行输入的第一次出现。添加一个 /g
标志来替换所有匹配项:
result=$(echo "$firstString" | sed "s/Suzi/$secondString/g")
result=$(echo $firstString | sed "s/Suzi/$secondString/g")
echo
参数周围添加了缺少的引号。它在不使用简单字符串引用的情况下具有欺骗性地工作,但很容易在任何重要的输入字符串(不规则间距、shell 元字符等)上中断。
尝试这个:
sed "s/Suzi/$secondString/g" <<<"$firstString"
如果字符串具有正则表达式字符,则使用 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。
sed
与 pwd
命令一起使用,以避免每次运行我的自定义 $PS1
时定义一个新变量。 Bash 是否提供了一种比魔术变量更通用的方法来使用命令的输出进行字符串替换?至于您的代码,我不得不转义 ~
以防止 Bash 将其扩展为 $HOME。另外,命令中的 #
有什么作用?
~
”:注意我是如何引用内容的。记住总是引用东西!这不仅适用于魔术变量:任何变量都能够在 bash 中进行替换、获取字符串长度等等。恭喜您快速尝试 $PS1
:如果您更熟悉另一种编程语言并希望编写已编译的提示,您可能也对 $PROMPT_COMMAND
感兴趣。
echo "${PWD/#$HOME/~}"
不会将我的 $HOME
替换为 ~
。将 ~
替换为 \~
或 '~'
有效。这些都可以在另一个发行版上的 Bash 4.2.53 上运行。您能否更新您的帖子以引用或转义 ~
以获得更好的兼容性?我的“魔术变量”问题的意思是:我可以在例如 uname
的输出上使用 Bash 的变量替换而不先将其保存为变量吗?至于我个人的$PROMPT_COMMAND
,it's complicated。
如果明天你决定不爱 Marry,她也可以被替换:
today=$(</tmp/lovers.txt)
tomorrow="${today//Suzi/Sara}"
echo "${tomorrow//Marry/Jesica}" > /tmp/lovers.txt
必须有 50 ways to leave your lover。
echo [string] | sed "s/[original]/[target]/g"
“s”的意思是“替代”
“g”表示“全局,所有匹配的事件”
g
标志被严重误解。没有它,sed
将替换每行中的第一个匹配项,但如果您不希望每行出现多次,则不需要 g
。 (通常你会在每行只能有一个匹配项的表达式中看到它,比如 s/.*everything.*/all of it/g
,显然你首先要匹配整行,所以你不可能多次匹配正则表达式)。
因为我不能添加评论。 @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}
使用 AWK:
firstString="I love Suzi and Marry"
echo "$firstString" | awk '{gsub("Suzi","Sara"); print}'
纯 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
这个怎么运作:
删除最小后缀模式。如果后缀 $t "Suzi*" 在 $f "I love Suzi and Marry" 中,"${f%$t*}" 返回 "I love"。
但如果 t=Zelda,则 "${f%$t*}" 不删除任何内容,并返回整个字符串 "I love Suzi and Marry"。
这用于测试 $t 是否在带有 [ "${f%$t*}" != "$f" ] 的 $f 中,如果 $f 字符串包含 "Suzi*" 则评估为 true,否则为 false .
如果测试返回 true,则使用 Remove Smallest Suffix Pattern ${f%$t*} "I love" 和 Remove Smallest Prefix Pattern ${f#*$t} "and Marry" 构造所需的字符串,并使用第二个字符串 $s “萨拉”介于两者之间。
我发现的唯一方法是将字符串存储在文件中,使用 sed 然后将文件内容存储在 var 中:
echo "I love Suzy" > tmp.txt
sed -i "s/Suzy/Sarah/" tmp.txt
set res=`cat tmp.txt`
echo $res
rm tmp.txt
我不知道我使用的是哪种 shell(如果我键入“sh”,我发现只有 sh-4.2),但所有经典语法都失败了,比如简单的 test=${test2}
。它失败了 2 次:分配时(必须使用 set
)和 ${}
。
$STRING="${STRING/\n/<br />}"
\n
将代表它自己,而不是换行符。我现在没有手边的 Bash 来测试,但您应该可以编写类似$STRING="${STRING/$'\n'/<br />}"
的内容。 (尽管您可能想要STRING//
-- replace-all -- 而不仅仅是STRING/
。)echo ${my string foo/foo/bar}
。你需要input="my string foo"; echo ${input/foo/bar}