Find and Replace Inside a Text File from a Bash Command
对于给定的输入字符串(如
我正在编写一个应用程序,并使用Ironpython通过ssh执行命令,但我不太了解Unix,也不知道该寻找什么。
我听说bash除了作为命令行界面之外,还可以是一种非常强大的脚本语言。所以,如果这是真的,我假设你可以执行这样的操作。
我可以用bash来完成它吗?实现目标的最简单(一行)脚本是什么?
最简单的方法是使用SED(或Perl):
由于
如果您真的想使用just bash,那么以下方法可以工作:
这会在每一行上循环,进行替换,并写入临时文件(不想破坏输入)。最后的移动只是将临时名称移动到原始名称。
文件操作通常不是由bash完成的,而是由bash调用的程序完成的,例如:
1 | > perl -pi -e 's/abc/XYZ/g' /tmp/file.txt |
有关更多详细信息,包括如何备份原始文件,请参阅
我很惊讶,因为我被这个绊倒了…
有一个"replace"命令随包"mysql server"一起提供,因此如果安装了该命令,请尝试:
1 2 3 4 5 | # replace string abc to XYZ in files replace"abc""XYZ" -- file.txt file2.txt file3.txt # or pipe an echo to replace echo"abcdef" |replace"abc""XYZ" |
更多关于这方面的信息,请参阅"替换人"…
这是一篇古老的文章,但是对于任何想使用变量的人来说,正如@centurian所说的,单引号意味着什么都不会被扩展。
获取变量的一个简单方法是进行字符串连接,因为这是通过在bash中并置来完成的,所以应该可以使用以下方法:
bash和其他shell一样,只是协调其他命令的工具。通常,您会尝试使用标准的UNIX命令,但是您当然可以使用bash来调用任何东西,包括您自己编译的程序、其他shell脚本、python和perl脚本等。
在这种情况下,有两种方法可以做到这一点。
如果要读取一个文件并将其写入另一个文件,请在执行搜索/替换时使用sed:
1 | sed 's/abc/XYZ/g' <infile >outfile |
如果要就地编辑文件(就像在编辑器中打开文件一样,编辑文件,然后保存文件),请向行编辑器"ex"提供说明。
1 2 3 4 | echo"%s/abc/XYZ/g w q " | ex file |
Ex就像没有全屏模式的vi。您可以在vi的":"提示下使用相同的命令。
在其他人中找到了这个线索,我同意它包含了最完整的答案,所以我也添加了我的答案:
1)SED和ED非常有用……用手!!!!看看@johnny的代码:
1 | sed -i -e 's/abc/XYZ/g' /tmp/file.txt |
2)当我的限制是通过shell脚本使用它时,不能在内部使用变量来代替abc或xyz!这似乎至少和我理解的一致。所以,我不能使用:
1 2 3 4 5 | x='abc' y='XYZ' sed -i -e 's/$x/$y/g' /tmp/file.txt #or, sed -i -e"s/$x/$y/g" /tmp/file.txt |
但是,我们能做什么?正如,@johnny所说,使用"while read…",但不幸的是,这并不是故事的结尾。以下内容对我很有用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #edit user's virtual domain result= #if nullglob is set then, unset it temporarily is_nullglob=$( shopt -s | egrep -i '*nullglob' ) if [[ is_nullglob ]]; then shopt -u nullglob fi while IFS= read -r line; do line="${line//'<servername>'/$server}" line="${line//'<serveralias>'/$alias}" line="${line//'<user>'/$user}" line="${line//'<group>'/$group}" result="$result""$line"' ' done < $tmp echo -e $result > $tmp #if nullglob was set then, re-enable it if [[ is_nullglob ]]; then shopt -s nullglob fi #move user's virtual domain to Apache 2 domain directory ...... |
3)可以看出,如果设置了nullglob,那么当有一个包含*的字符串时,它会表现得很奇怪,如中所示。
1 2 | <VirtualHost *:80> ServerName www.example.com |
成为
1 | <VirtualHost ServerName www.example.com |
没有结束角支架,Apache2甚至不能加载!
4)这种解析应该比点击搜索和替换慢,但是,正如您已经看到的,在一个解析周期中,有4个变量用于4种不同的搜索模式!
根据对问题的假定,我能想到最合适的解决方案。
可以使用SED
1 | sed -i 's/abc/XYZ/gi' /tmp/file.txt |
如果不确定要查找的文本是
如果现在没有您的文件名,您可以使用
1 | find ./ -type f -exec sed -i 's/abc/XYZ/gi' {} \; |
在所有python文件中查找和替换:
1 | find ./ -iname"*.py" -type f -exec sed -i 's/abc/XYZ/gi' {} \; |
您也可以使用ed命令在文件搜索和替换中执行以下操作:
1 2 3 | # delete all lines matching foobar ed -s test.txt <<< $'g/foobar/d w' |
在bash hacker网站上查看更多信息
如果用"/"字符替换URL,请小心。
如何操作的示例:
1 | sed -i"s%http://domain.com%http://www.domain.com/folder/%g""test.txt" |
摘自:http://www.sysadment.com/2015/07/linux-reemplazar-texto-en-archivos-con-sed.html
如果您正在处理的文件不太大,临时将其存储在变量中没有问题,那么您可以立即对整个文件使用bash字符串替换-不需要一行一行地遍历它:
1 2 | file_contents=$(</tmp/file.txt) echo"${file_contents//abc/XYZ}"> /tmp/file.txt |
整个文件内容将被视为一个长字符串,包括换行符。
xyz可以是一个变量,例如
尝试以下shell命令:
1 | find ./ -type f -name"file*.txt" | xargs sed -i -e 's/abc/xyz/g' |
要以非交互方式编辑文件中的文本,需要就地文本编辑器,如vim。
下面是如何从命令行使用它的简单示例:
1 | vim -esnc '%s/foo/bar/g|:wq' file.txt |
这相当于前编辑的@slim answer,基本上是一样的。
这里有几个
将文件中的文本
1 | ex -s +%s/foo/bar/ge -cwq file.txt |
删除多个文件的尾随空格:
1 | ex +'bufdo!%s/\s\+$//e' -cxa *.txt |
故障排除(终端卡住时):
- 添加
-V1 参数以显示详细消息。 - 强制退出:
-cwq! 。
参见:
- 如何以非交互方式编辑文件(例如,在管道中)?在六月份
您也可以在bash脚本中使用python。我在这里的一些顶级答案上没有太大的成功,并且发现这可以在不需要循环的情况下工作:
1 2 3 4 5 6 7 8 9 10 11 12 | #!/bin/bash python filetosearch = '/home/ubuntu/ip_table.txt' texttoreplace = 'tcp443' texttoinsert = 'udp1194' s = open(filetosearch).read() s = s.replace(texttoreplace, texttoinsert) f = open(filetosearch, 'w') f.write(s) f.close() quit() |
您可以使用rpl命令。例如,您希望在整个PHP项目中更改域名。
1 | rpl -ivRpd -x'.php' 'old.domain.name' 'new.domain.name' ./path_to_your_project_folder/ |
这不是一个明确的原因,但它是一个非常迅速和有用的。:)