使用bash或zshell之类的shell,如何进行递归“查找并替换”?换句话说,我想在此目录及其子目录的所有文件中将所有出现的'foo'替换为'bar'。
使用bash或zshell之类的shell,如何进行递归“查找并替换”?换句话说,我想在此目录及其子目录的所有文件中将所有出现的'foo'替换为'bar'。
Answers:
该命令将执行此操作(在Mac OS X Lion和Kubuntu Linux上都经过测试)。
# Recursively find and replace in files
find . -type f -name "*.txt" -print0 | xargs -0 sed -i '' -e 's/foo/bar/g'
运作方式如下:
find . -type f -name '*.txt'
在当前目录(.
)和以下目录中查找-type f
名称以结尾的所有常规文件().txt
|
将命令的输出(文件名列表)传递给下一个命令xargs
收集这些文件名并一一交给 sed
sed -i '' -e 's/foo/bar/g'
表示“在没有备份的情况下就地编辑文件,并且s/foo/bar
每行(/g
)多次进行以下替换()”(请参阅man sed
)请注意,第4行中的“无需备份”部分对我来说还可以,因为无论如何我要更改的文件都受版本控制,因此如果出现错误,我可以轻松撤消。
-print0
选项,就永远无法通过管道找到到xargs的输出。您的命令将对名称中带有空格等的文件失败。
find -name '*.txt' -exec sed -i 's/foo/bar/g' {} +
使用GNU find就能完成所有这些工作。
sed: can't read : No such file or directory
运行时得到提示find . -name '*.md' -print0 | xargs -0 sed -i '' -e 's/ä/ä/g'
,但find . -name '*.md' -print0
列出了许多文件。
-i
和''
''
后,sed -i
有什么''
作用?
如果您使用的是Git,则可以执行以下操作:
git grep -lz foo | xargs -0 sed -i '' -e 's/foo/bar/g'
-l
仅列出文件名。-z
在每个结果之后输出一个空字节。
我之所以结束此操作,是因为项目中的某些文件在文件末尾没有换行符,即使没有其他更改,sed也添加了换行符。(没有评论文件末尾是否应该有换行符。)
find ... -print0 | xargs -0 sed ...
解决方案不仅需要花费更长的时间,而且还会向尚未添加换行符的文件中添加换行符,这对于在git repo中进行操作很麻烦。git grep
相比之下,照明速度很快。
尝试:
sed -i 's/foo/bar/g' $(find . -type f)
在Ubuntu 12.04上测试。
如果子目录名称和/或文件名包含空格,则此命令将不起作用,但如果确实包含空格,请不要使用此命令,因为它将不起作用。
在目录名和文件名中使用空格通常是一个坏习惯。
http://linuxcommand.org/lc3_lts0020.php
查看“关于文件名的重要事实”
现在,我使用此shell脚本,它将我从其他答案和搜索网络中学到的东西结合在一起。我将其放置在我的文件change
夹中名为的文件中,$PATH
并做了chmod +x change
。
#!/bin/bash
function err_echo {
>&2 echo "$1"
}
function usage {
err_echo "usage:"
err_echo ' change old new foo.txt'
err_echo ' change old new foo.txt *.html'
err_echo ' change old new **\*.txt'
exit 1
}
[ $# -eq 0 ] && err_echo "No args given" && usage
old_val=$1
shift
new_val=$1
shift
files=$* # the rest of the arguments
[ -z "$old_val" ] && err_echo "No old value given" && usage
[ -z "$new_val" ] && err_echo "No new value given" && usage
[ -z "$files" ] && err_echo "No filenames given" && usage
for file in $files; do
sed -i '' -e "s/$old_val/$new_val/g" $file
done
以下命令在Ubuntu和CentOS上运行良好;但是,在OS XI下不断出现错误:
find . -name Root -exec sed -i 's/1.2.3.4\/home/foo.com\/mnt/' {} \;
sed:1:“ ./ Root”:无效的命令代码。
当我尝试通过xargs传递参数时,它工作正常,没有错误:
find . -name Root -print0 | xargs -0 sed -i '' -e 's/1.2.3.4\/home/foo.com\/mnt/'
-i
为-i ''
的事实可能比更改-exec
为的事实更相关-print0 | xargs -0
。顺便说一句,您可能不需要-e
。