Nat*_*ong 120 bash zsh shell find-and-replace
使用像 bash 或 zshell 这样的 shell,如何进行递归的“查找和替换”?换句话说,我想在这个目录及其子目录中的所有文件中用 'bar' 替换每次出现的 'foo'。
Nat*_*ong 150
此命令将执行此操作(在 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'
Run Code Online (Sandbox Code Playgroud)
这是它的工作原理:
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"
Run Code Online (Sandbox Code Playgroud)
Zty*_*tyx 41
find . -type f -name "*.txt" -exec sed -i'' -e 's/foo/bar/g' {} +
Run Code Online (Sandbox Code Playgroud)
这消除了xargs
依赖性。
Dav*_*cki 16
如果您使用的是 Git,那么您可以这样做:
git grep -lz foo | xargs -0 sed -i '' -e 's/foo/bar/g'
Run Code Online (Sandbox Code Playgroud)
-l
只列出文件名。-z
在每个结果后打印一个空字节。
我最终这样做是因为项目中的某些文件在文件末尾没有换行符,并且 sed 即使没有进行其他更改也添加了换行符。(不评论文件末尾是否应该有换行符。)
尝试:
sed -i 's/foo/bar/g' $(find . -type f)
Run Code Online (Sandbox Code Playgroud)
在 Ubuntu 12.04 上测试。
编辑:
如果子目录名称和/或文件名包含空格,则此命令将不起作用,但如果您确实有它们,请不要使用此命令,因为它不起作用。
在目录名和文件名中使用空格通常是一种不好的做法。
http://linuxcommand.org/lc3_lts0020.php
查看“有关文件名的重要事实”