使用 bash 或 zshell 之类的 shell,如何进行递归“查找和替换”?换句话说,我想将此目录及其子目录中的所有文件中的每个“foo”替换为“bar”。
答案1
此命令可以完成此操作(已在 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 行中的“没有备份”部分对我来说是可以的,因为我更改的文件无论如何都在版本控制之下,所以如果出现错误,我可以轻松撤消。
为了避免记住这一点,我使用交互式 bash 脚本,如下所示:
#!/bin/bash
# find_and_replace.sh
echo "Find and replace in current directory!"
echo "File pattern to look for? (eg '*.txt')"
read filepattern
echo "Existing string?"
read existing
echo "Replacement string?"
read replacement
echo "Replacing all occurences of $existing with $replacement in files matching $filepattern"
find . -type f -name $filepattern -print0 | xargs -0 sed -i '' -e "s/$existing/$replacement/g"
答案2
find . -type f -name "*.txt" -exec sed -i'' -e 's/foo/bar/g' {} +
这将消除xargs
依赖性。
答案3
如果你使用 Git,那么你可以这样做:
git grep -lz foo | xargs -0 sed -i '' -e 's/foo/bar/g'
-l
仅列出文件名。-z
在每个结果后打印一个空字节。
我最终这样做是因为项目中的某些文件在文件末尾没有换行符,而 sed 即使没有进行其他更改也会添加换行符。(对于文件末尾是否应该有换行符,没有评论。
答案4
这是我为此使用的 zsh/perl 函数:
change () {
from=$1
shift
to=$1
shift
for file in $*
do
perl -i.bak -p -e "s{$from}{$to}g;" $file
echo "Changing $from to $to in $file"
done
}
我会使用
$ change foo bar **/*.java
(例如)