如何在不使用命令Sed的情况下查找和替换字符串?


16

大家都知道,sed是大大有效地查找和替换字符串,例如查找“a”和它替换到“b”: sed 's/a/b/g'

是否可以用其他命令或shell脚本代替sed

这是针对没有该sed命令的裁剪过的Linux电视系统。所以我必须使用其他命令或脚本来代替sed 's/a/b/g'. –


实际上,这仅仅是基于正则表达式的替换。任何能够处理这种事情的工具或语言就可以做同样的,但不同的语法:$var=~s/a/b/ggsub(/a/,"b",var)var.gsub(/a/,'b')var.replace(/a/g,'b')preg_replace("/a/","b",$var)regsub -all a b $var。除此之外,许多工具和语言还可以进行纯文本字符串替换。因此,您的问题有点广泛。
manatwork 2013年

1
为什么?您要解决什么问题?
吉尔(Gilles)'所以

用于电视的裁剪好的Linux系统尚未sed命令。所以我必须使用其他命令或脚本来代替sed's / a / b / g'。
binghenzq

Answers:


12

是的,有多种方法可以做到这一点。您也可以使用awkperlbash进行这些活动。总的来说,这sed可能是执行这些类型任务的最合适的工具。

例子

说我在文件中有此样本数据data.txt

foo bar 12,300.50
foo bar 2,300.50
abc xyz 1,22,300.50

awk

$ awk '{gsub("foo", "foofoofoo", $0); print}' data.txt 
foofoofoo bar 12,300.50
foofoofoo bar 2,300.50
abc xyz 1,22,300.50

佩尔

$ perl -pe "s/foo/foofoofoo/g" data.txt 
foofoofoo bar 12,300.50
foofoofoo bar 2,300.50
abc xyz 1,22,300.50

内联编辑

上面的示例也可以直接修改文件。Perl的例子很简单。只需添加-i开关。

$ perl -pie "s/foo/foofoofoo/g" data.txt 

因为awk它不那么直接,但同样有效:

$ { rm data.txt && awk '{gsub("foo", "foofoofoo", $0); print}' > data.txt; } < data.txt

此方法创建一个带有花括号'{...}`的子外壳,文件通过以下方式重定向到其中:

$ { ... } < data.txt

一旦文件被重定向到子Shell中,它将被删除,然后awk针对读取到子Shell STDIN中的文件内容运行。然后,该内容将由awk我们删除的同一文件名进行处理并写回,从而有效地替换了它。


谢谢您的回答,我将在下一个工作日进行尝试。但是我不确定是否能正常工作,因为在裁剪过的Linux电视系统中可能不存在某些命令,例如'sed'。所以我仍然想使用'find'命令,“ grep”等解决方案。
binghenzq 2013年

@binghenzq-我添加了内联编辑文件的示例。
slm

-1我很少投票,但在这种情况下,问题的重点似乎是一种更简单的方法,而不是其他更为/相当复杂的方法,并且可能也有依赖性。如果问题只是关于完整* nix机器安装的替代方案,那么我可能会对这个原本不错的答案+1。
Michael Durrant

@MichaelDurrant-我刚刚添加了OP要求的那些详尽的内联编辑。OP还设置了使用sedI 的要求。Sed是进行此类替换的合适工具,他显然是在要求更好地理解这些工具的作用,因此向人们展示这些东西虽然不好,但在展示方面非常受教育他们为什么。知识分子中的ppl太多次只是在不解释原因的情况下简单地说“不做”,所以我是。但是,至少要感谢您对为什么选择DV发表评论。
slm

当然,我认为这在所有其他方面都是一个很好的答案。是的,我讨厌-1而没有任何解释。
Michael Durrant

13

单字母替换的经典替代方法是该tr命令,该命令几乎可以在任何系统上使用:

$ echo "foobar" | tr a b   
foobbr

trsed实际上比这更好,因为对单个字母替换使用sed(更不用说perlawk)就像使用大锤杀死苍蝇一样。

grep 不是为此设计的,它不会修改其输入,而只会搜索它。

另外,您可以使用某些外壳的替代功能。这里使用kshzshbash语法:

$ foo="foobar"
$ echo "${foo//a/b}"
foobbr

如果您确切说明了您要解决的问题,我们可以为您提供更具体的答案。


是否可以忽略大小写${foo//a/b}
AlikElzin-kilaka

@ AlikElzin-kilaka恐怕不是。您将不得不使用一些更复杂的东西,例如:echo "$foo" | sed 's/a/b/i或给一个字符类:echo ${foo//[aA]/b}
terdon

4

您可以在Ex模式下使用Vim:

ex -s -c '%s/a/b/g|x' file
  1. % 选择所有行

  2. s 替代

  3. g 全球替代

  4. x 保存并关闭


太谢谢了。只是要添加,-c标志是在编辑开始时执行命令(因为ex是编辑器),而-s标志要么是脚本模式禁用反馈,要么像是slient-mode。ref有关更多信息:ex-vi.sourceforge.net/ex.html
Jimmy MG Lim

3

如果您使用的是文件而不是流,则可以使用标准的文本编辑器ed

printf '%s\n' ',s/a/b/g' w q | ed file.txt

这应该在任何* nix上可用。逗号',s/a/b/g'指示ed要在每一行上工作(您也可以使用%,如果您习惯使用vim会更熟悉),其余部分是标准的搜索和替换。w告诉它写入(保存)文件,q告诉它退出。

请注意,与sed的-i选项(以及其他工具中的类似选项)不同,这实际上是在原地编辑文件,而不是使用临时文件作弊。

我认为不可能将其与流一起使用,但是我对此并不十分了解ed,如果它确实具有该功能(Unix哲学就是它的意思),我也不会感到惊讶。


2

使用ancestor 命令(这-s意味着安静(无声),并且在命令之前使用逗号表示在所有行上执行):

只需在STDOUT上打印:

ed -s file <<!
,s/a/b/g
,p
q
!

就地替换:

ed -s file <<!
,s/a/b/g
w
q
!
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.