如何從命令列進行遞歸查找和替換?

如何從命令列進行遞歸查找和替換?

使用 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'

它的工作原理如下:

  1. find . -type f -name '*.txt'尋找目前目錄 ( ) 及以下目錄中名稱以以下字元結尾的.所有常規檔案 ( )-type f.txt
  2. |將該命令的輸出(檔案名稱列表)傳遞給下一個命令
  3. xargs收集這些檔案名稱並將它們一一交給sed
  4. 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

(例如)

相關內容