使用Linux命令在大文件中替换字符串为另一个字符串

8
我有一个巨大的SQL文件需要在服务器上执行。这个转储文件来自我的机器,在其中有一些与我的机器相关的设置。因此,基本上,我希望将每个出现的"c://temp"替换为"//home//some//blah"。如何从命令行完成这个操作?

你的命令缺少一个尾随的百分号(%)。正确的格式应该是s%foo%bar%,而不是s%foo%bar。 - Vinko Vrsalovic
7个回答

31

sed是处理大文件的不错选择。

sed -i.bak -e 's%C://temp%//home//some//blah%' large_file.sql

这是一个很好的选择,因为它不会一次性读取整个文件进行更改。引用手册的说法:
“流编辑器用于在输入流(文件或来自管道的输入)上执行基本文本转换。虽然在某些方面类似于允许脚本编辑的编辑器(例如ed),但sed仅通过对输入进行一次遍历来工作,并因此更有效。但是,sed之所以能够过滤管道中的文本,特别区别于其他类型的编辑器。”
相关的手册部分在这里。以下是简要说明:
-i.bak启用就地编辑并保留带有.bak扩展名的备份副本
s%foo%bar%使用s,即替换命令,它将在%符号之间匹配第一个字符串'foo'的匹配项替换为第二个字符串'bar'。它通常写成s//,但由于您的字符串有大量斜杠,更方便的做法是将它们更改为其他内容,以避免必须转义它们。
示例:
vinko@mithril:~$ sed -i.bak -e 's%C://temp%//home//some//blah%' a.txt
vinko@mithril:~$ more a.txt
//home//some//blah
D://temp
//home//some//blah
D://temp
vinko@mithril:~$ more a.txt.bak
C://temp
D://temp
C://temp
D://temp
这段代码是用sed命令将a.txt文件中的"C://temp"替换为"//home//some//blah",并备份原文件为a.txt.bak。more命令用于查看文件内容。

2
你可以使用不同的字符来避免引用斜杠,例如sed -e"s%C://temp%/home//some//blah%"。 另外,当你确定选项时,-i选项允许你原地保存文件。 - dalloliogm
这是我正在输入的命令: sed -i.bak -e 's%C:\temp%/home/liveon/public_html/tmp' liveon.sql这是我收到的错误信息: sed: -e 表达式 #1,第41个字符:未终止的`s'命令有人能帮忙吗? - rockstardev
此外,RD,请确保正确转义反斜杠。 - Dave Jarvis

12

只是为了完整性。使用perl进行就地替换。

perl -i -p -e 's{c://temp}{//home//some//blah}g' mysql.dmp

也不需要反斜杠转义。 ;)


10
请注意,如果您在不带扩展名的情况下使用“-i”标志,则没有备份。如果您想要备份,请尝试使用“-i.bak”,这将进行就地编辑,并免费为您提供原始文件的备份,命名为“original.bak”。 - Telemachus
我让我的版本控制系统处理备份。 - jrockway
4
@Jrockway: 对你来说很好,但它假设所涉及的文件在版本控制之下,并且你知道 -i.bak 的作用并选择不使用它。我只希望那些推荐使用 -i 开关的人能花两秒钟时间解释一下 -i 和 -i.bak 之间的区别。如果你玩弄的文件没有受到版本控制,并且你犯了一个简单的打字错误(例如忘记了 -p 标志),那么这将真的会造成很大的问题。 - Telemachus

4

试试sed?类似这样:

sed 's/c:\/\/temp/\/\/home\/\/some\/\/blah/' mydump.sql > fixeddump.sql

转义所有这些斜杠使得它看起来很可怕,下面是一个更简单的示例,将 foo 更改为 bar。

sed 's/foo/bar/' mydump.sql > fixeddump.sql

正如其他人所指出的,您可以选择自己的分隔符,这将防止在此情况下出现倾斜牙签综合症

sed 's|c://temp\\|home//some//blah|' mydump.sql > fixeddump.sql

sed的巧妙之处在于它对流进行操作而不是一次性处理整个文件,因此您可以使用较少的内存处理大文件。

谢谢Paul!Intellij Idea变得疯狂了,而用sed只需要1秒钟就可以在我的SQL文件中将反斜杠替换为双反斜杠。 - humkins

3

此外,还有一种非标准的UNIX实用工具rpl,它可以执行与sed示例完全相同的操作。但是,我不确定rpl是否按流进行操作,因此在这里使用sed可能更好。


嘿,你碰巧是rpl开发者的朋友吗? :-) - Vinko Vrsalovic
不,除了工具之外我从未听说过这个人;有一次我需要在几千个文本文件上进行批量替换,它派上了用场,所以我一直将其放在我的工具箱里。 - Meredith L. Patterson
在这种情况下,说明推荐的原因是值得的(或者你可能会这么做,因为你似乎半推半就)。也就是说,与其仅仅提供一个实用程序的名称,还请告诉我们您喜欢它的原因。 - Telemachus
3
Rpl适用于简单替换,因为它的语法比它所替代的sed和find的组合更加用户友好。它还有一个很棒的模拟运行功能,可以告诉你它会替换什么,而不会真正执行替换操作。它的主要限制在于它只能进行直接替换,不能使用正则表达式。 - Tyler McHenry
@Telemachus - Tyler nailed it. @Telemachus - Tyler做得很好。 - Meredith L. Patterson

1
perl -pi -e 's#c://temp#//home//some//blah#g' yourfilename

-p选项将此脚本视为循环,它将逐行读取指定的文件并运行正则表达式搜索和替换。

-i此标志应与-p标志一起使用。这个命令让Perl原地编辑文件。

-e只是执行这个Perl代码的意思。

祝你好运


1

sed 命令可以实现这个功能。你可以选择一个不同的分隔符(在本例中为 _),而无需转义斜线。

sed -e 's_c://temp/_/home//some//blah/_' file1.txt > file2.txt

你错过了最后一个下划线:"s_c://temp//home//some//blah" - dalloliogm

1

gawk

awk '{gsub("c://temp","//home//some//blah")}1' file

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接