Replace one substring for another string in shell script
我有"我爱苏西并结婚",我想把"苏西"改成"萨拉"。
1 2 3 4
| #!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
# do something... |
结果必须如下:
1
| firstString="I love Sara and Marry" |
要用给定的字符串替换模式的第一个匹配项,请使用${parameter/pattern/string}:
1 2 3 4 5
| #!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
echo"${firstString/Suzi/$secondString}"
# prints 'I love Sara and Marry' |
要替换所有事件,请使用${parameter//pattern/string}:
1 2 3
| message='The secret code is 12345'
echo"${message//[0-9]/X}"
# prints 'The secret code is XXXXX' |
(这记录在bash参考手册和第3.5.3节"shell参数扩展"中。)
请注意,这个特性不是由posix指定的,它是bash扩展,因此并非所有的unix shell都实现它。有关POSIX的相关文档,请参阅OpenGroup技术标准基本规范,第7期,Shell&utilities卷,以及第2.6.2节"参数扩展"。
- @Ruakh我该如何写这个带有或条件的语句。如果我想取代苏子或嫁给新的字符串。
- @Priyatham51:没有内置的功能。先换一个,然后换另一个。
- @谢谢你的回复。我昨天已经这样做了,我只是想和你确认一下,如果有选择的话,这样我就不必写两行代码了。:)
- 将"n"(换行符)替换为"
"(HTML换行符)是否有效?$STRING="${STRING/
/
}"
- @布鲁:不,因为在这种情况下,
将代表自己,而不是一个新行。我现在没有现成的bash来测试,但您应该能够编写类似于$STRING="${STRING/$'
'/
}"的东西。(尽管你可能想用STRING//--全部替换--而不是仅仅用STRING/.)。
- 如果原始字符串包含"/home/user/dir/",我想将"/home/usr"替换为"/home"(获取结果"/home/dir/")?我如何才能摆脱"/"本身的含义?
- @Deniomariz:foo=/home/user/dir,后面是echo"${foo/\/home\/user//home}",将打印/home/dir。
- 要清楚,因为这让我有点困惑,第一部分必须是一个变量引用。你不能做echo ${my string foo/foo/bar}。你需要input="my string foo"; echo ${input/foo/bar}。
- @ruakh-mary通常用一个r:d拼写。
- @JobJob:谁在乎"通常"的拼写?这首诗写的是《江户记》(12),故事的结尾。
- @哦,该死的-他们就这么做了!我的道歉,应该是对手术的评论。要清楚的是-只是有点笑:d
- @Deniomariz我有foo ="$(pwd)"和bar="/test/",我现在怎么用echo"${foo/bar/profi/}"
- 注意:如果替换字符串包含斜杠,只需转义它们。path=/home/me/docs; echo"${path/me\/docs/you\/docs}"
- @这是我的用例
这完全可以通过bash字符串操作完成:
1 2 3
| first="I love Suzy and Mary"
second="Sara"
first=${first/Suzy/$second} |
这将只替换第一个匹配项;要全部替换,请将第一个斜杠加倍:
1 2 3 4
| first="Suzy, Suzy, Suzy"
second="Sara"
first=${first//Suzy/$second}
# first is now"Sara, Sara, Sara" |
- 有一个重复接受的答案,而不是用全局替换选项编辑接受的答案,这有什么意义呢?并添加了regexps在执行时受支持。并解释"糟糕的替换"是怎么回事。你有足够的分数,@kevin:)
试试这个:
1
| sed"s/Suzi/$secondString/g" <<<"$firstString" |
- 实际上您不需要SED;bash支持这种本地替换。
- 我猜这是标记为"bash"的,但之所以出现在这里,是因为需要为另一个shell做一些简单的事情。与wiki.ubuntu.com/&hellip;让它看起来像是我需要的东西相比,这是一个很好的简洁的选择。
- 这对ash/dash或任何其他posix sh都很有用。
- 我得到错误的sed:-e表达式1,char 9:未知选项到's
- @事实上,我发现这对干草堆串很大的情况很有用。另一个选择是我得到了zsh: command too long。
- 第一个适用于stdin的答案,非常适合于管道字符串。
- @这个答案适用于管道。像my_command | sed ... | ...一样
- @namgvu或其他任何出现此错误的人,通常意味着搜索或替换节中的一个字符串与分隔符具有相同的字符。例如,通常使用/作为分隔符,但如果字符串包含*nix目录,则会看到该错误,因为它们也具有/字符。
如果字符串有regexp字符,那么使用bash比使用sed要好。
1
| echo ${first_string/Suzi/$second_string} |
它可移植到Windows中,至少与bash 3.1一样旧。
为了证明你不需要太担心逃跑,让我们来看看:
进入这个:
但前提是/home/name是在开始的时候。我们不需要sed!
考虑到bash给了我们神奇的变量$PWD和$HOME,我们可以:
编辑:感谢Mark Haferkamp对引用/转义~注释的评论。*
注意变量$HOME如何包含斜线,但这并没有破坏任何东西。
进一步阅读:高级bash脚本指南。如果必须使用sed,请确保转义每个字符。
- 这个答案阻止了我使用sed和pwd命令,以避免每次运行自定义$PS1时定义一个新变量。bash是否提供了比magic变量更通用的方法来使用命令的输出来替换字符串?至于您的代码,我必须避开~,以防止bash将其扩展到$home。还有,你指挥的江户十一〔四〕是做什么的?
- @markhaferkamp从"进一步阅读建议"链接中查看。关于"逃离~":注意我是如何引用这些东西的。记住总是引用一些东西!这不仅仅适用于magic变量:任何变量都可以在bash中进行替换、获取字符串长度等等。恭喜您尝试快速使用$PS1:如果您对另一种编程语言更熟悉,并且希望对编译后的提示进行编码,那么您也可能对$PROMPT_COMMAND感兴趣。
- "进一步阅读"链接解释了""。在bash 4.3.30上,echo"${PWD/#$HOME/~}"没有用~替换我的$HOME。用\~或'~'工程代替~。在另一个发行版上的bash 4.2.53上的任何这些工作。为了更好的兼容性,您能更新您的文章来引用或退出~吗?我的"魔法变量"问题的意思是:我可以在不首先将其保存为变量的情况下,在uname的输出上使用bash的变量替换吗?至于我的个人$PROMPT_COMMAND,这很复杂。
- @马克哈弗坎普,哇,你完全是对的,我的错。将立即更新答案。
- 我好像错了……实际上,在chakra linux和opensuse之间重新启动(而不是chrooting)表明,${PWD/#$HOME/~}在suse上的bash 4.2.53中工作,${PWD/#$HOME/\~}在chakra上的bash 4.3.30中工作,但反之则不一样。在两个发行版上都有效的解决方法是用$(echo '~')替换~,就像在冗长的${PWD/#$HOME/$(echo '~')}中一样。编辑:我刚意识到$'~'可能更好。我正在测试它。
- 请忽略我以前评论中的编辑。$'~'在echo命令中效果很好,但是当我试图用它在$ps1中得到一个文本~时,只引起了我的沮丧。$(echo '~')似乎是最好的解决方法。
- @马克哈费尔坎普巴什及其模糊的陷阱…P
对于dash,所有以前的帖子都不起作用
posix sh兼容的解决方案是:
1
| result=$(echo"$firstString" | sed"s/Suzi/$secondString/") |
- 我收到这个:$echo$(echo$firststring sed's/suzi/$secondstring/g),我爱$secondstring并结婚。
- @qstnr_la使用双引号替换变量:result=$(echo $firstString | sed"s/Suzi/$secondString/g")。
- 加1表示如何输出到变量。谢谢!
- 我修复了单引号,并在echo参数周围添加了缺失的引号。它可以在不引用简单字符串的情况下进行欺骗,但很容易在任何重要的输入字符串(不规则间距、shell元字符等)上中断。
- 在sh(aws codebuild/ubuntu sh)中,我发现在末尾需要一个斜线,而不是一个双斜线。我将编辑注释,因为上面的注释也显示一个斜线。
如果明天你决定不爱结婚,她也可以被取代:
1 2 3
| today=$(</tmp/lovers.txt)
tomorrow="${today//Suzi/Sara}"
echo"${tomorrow//Marry/Jesica}"> /tmp/lovers.txt |
必须有50种方法离开你的爱人。
纯posix shell方法与基于Roman Kazanovskyi的sed的答案不同,它不需要外部工具,只需要shell自己的本地参数扩展。请注意,长文件名被最小化,因此代码更适合一行:
1 2 3 4 5
| f="I love Suzi and Marry"
s=Sara
t=Suzi
["${f%$t*}" !="$f" ] && f="${f%$t*}$s${f#*$t}"
echo"$f" |
输出:
它是如何工作的:
删除最小后缀模式。如果后缀$t中的"Suzi*在$f中,I loveSuzi and Marry中,"${f%$t*}"返回"EDOCX1〔13]。
但如果t=Zelda,则"${f%$t*}"不删除任何内容,并返回整个字符串"I love Suzi and Marry"。
用于测试$t是否在$f中,["${f%$t*}" !="$f" ]是否在$f中,如果$f字符串包含"Suzi*则评估为真,否则评估为假。
如果测试返回true,则使用删除最小后缀模式${f%$t*}"I love"构造所需字符串,并删除最小前缀模式${f#*$t}"and Marry",其中第二个字符串$s"Sara"。
因为我不能添加评论。@Ruaka为了使示例更易读,请这样写
1 2 3 4 5 6
| 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} |