
使用 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
(例如)