2013-03-14 83 views
147

我需要在目錄內的所有文件和子目錄中遞歸搜索指定的字符串,並將此字符串替換爲另一個字符串。如何grep和替換

我知道的命令找出它可能是這樣的:

grep 'string_to_find' -r ./* 

但我怎麼能代替的string_to_find每個實例與另一個字符串?

+0

我不相信grep可以做到這一點(我可能是錯的)。更簡單的方法是使用sed或perl來替換 – 2013-03-14 06:41:40

+1

嘗試使用'sed -i's /.*子字符串*/replace /'' – 2013-03-14 06:42:09

+1

@Eddy_Em這將用replace代替整行。您需要使用分組來捕獲子字符串前後的部分行,然後將其放入替換行中。 'sed -i's/\(。* \)substring \(。* \)/ \ 1replace \ 2 /'' – JStrahl 2014-08-05 07:50:37

回答

1

通常不是用grep,而是用sed -i 's/string_to_find/another_string/g'perl -i.bak -pe 's/string_to_find/another_string/g'

102

我得到了答案。

grep -rl matchstring somedir/ | xargs sed -i 's/string1/string2/g' 
+11

這將掃描兩次匹配的文件...一次使用'grep',然後使用'sed '。使用'find'方法更高效,但是您提到的這種方法確實有效。 – cmevoli 2013-03-14 10:27:18

+24

在OS X上,您需要將'sed -i's/str1/str2/g''更改爲'sed -i'「's/str1/str2/g''才能正常工作。 – jdf 2015-07-07 22:53:01

+2

@jdf這是爲什麼? – chishaku 2016-07-26 15:16:07

158

另一個選擇是使用find然後通過sed傳遞它。

find /path/to/files -type f -exec sed -i 's/oldstring/new string/g' {} \; 
+24

在OS X 10.10終端上,需要一個到參數'-i'的正確擴展字符串。例如,'find/path/to/files -type f -exec sed -i'「」s/oldstring/new string/g「{} \;'無論如何,提供空字符串仍然會創建一個備份文件, ... – Eonil 2015-06-25 02:41:06

+5

爲什麼我會得到「sed:RE錯誤:非法字節序列」。是的,我爲OS X添加了「-i」「',否則它會起作用。 – taco 2016-06-16 19:51:01

+0

我在macOS 10.12上有非法字節序列問題,並且這個問題/答案解決了我的問題:http://stackoverflow.com/questions/19242275/re-error-illegal-byte-sequence-on-mac-os-x 。 – abeboparebop 2017-04-11 08:12:14

25

這個最適合我的OS X:

grep -r -l 'searchtext' . | sort | uniq | xargs perl -e "s/matchtext/replacetext/" -pi 

來源:http://www.praj.com.au/post/23691181208/grep-replace-text-string-in-files

+0

這是完美的!也適用於ag:'ag「search」-l -r。 |排序| uniq | xargs perl -e's/search/replace'-pi' – 2016-03-04 11:24:59

+1

'sort -u'可以代替'sort | uniq' – 2016-03-05 00:41:14

+0

@sebastiankeller你的Perl命令缺少最後一個斜槓,這是一個語法錯誤。 – tripleee 2016-06-11 08:12:13

0

另一種選擇是隻用perl與globstar。

在您的.bashrc(或任何地方)啓用shopt -s globstar允許** glob模式遞歸匹配所有子目錄和文件。

因此使用perl -pXe 's/SEARCH/REPLACE/g' -i **將遞歸地 替換SEARCHREPLACE

-X標誌告訴perl「禁用所有警告」 - 這意味着它不會抱怨目錄。

的globstar還允許你做這樣的事情sed -i 's/SEARCH/REPLACE/g' **/*.ext如果你想與REPLACE在所有子文件擴展名爲.ext更換SEARCH

+0

*「另一種選擇是使用perl和globstar ...」* - 不在Posixy機器上,如Solaris。這就是爲什麼我特意尋找'grep'和'sed'。 – jww 2017-10-25 00:20:31

19

你甚至可以遵循這樣的..

grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g' 

這將爲字符串中的所有文件的相對「窗口」搜索到當前目錄和替換「窗口'與'linux',每個文件中每個字符串的出現次數。

+2

只有存在不應修改的文件時,'grep'纔有用。在所有文件上運行'sed'會更新文件的修改日期,但如果沒有匹配則保持內容不變。 – tripleee 2016-06-11 08:10:46

+0

@tripleee:注意* ...但[sed]保持內容不變,如果沒有匹配「*。當使用'-i'時,我相信'sed'會改變它接觸到的每個文件的文件時間,甚至雖然內容沒有變化,但是'sed'也會轉換行結束符,因爲所有的'CRLF'都被改爲'LF',所以我沒有在Windows的'sed'中使用git repo。 – jww 2017-10-25 00:19:01

3

其他解決方案混合使用正則表達式語法。使用Perl/PCRE模式爲搜索和替換,避免加工的每一個文件,這個工作得很好:

grep -rlZP 'match1' | xargs -0r perl -pi -e 's/match2/replace/g;' 

其中match1match2通常是相同的,但match1可以簡化去除更多的先進功能,只與替代有關,例如捕獲組。

翻譯︰grep遞歸和列出匹配的文件,由nul分隔以保護文件名中的任何特殊字符,匹配此PCRE模式,然後管這些文件名xargs期望一個空分隔的列表,但不會如果沒有收到任何名字,請做任何事情,然後讓perl重寫每個文件,替換找到匹配的行。

I選項添加到grep以忽略二進制文件。

+0

Perl本身非常有能力遞歸一個文件結構,事實上,有一個工具['find2perl'](https://perldoc.perl.org/5.8.8/find2perl.html),它隨Perl一起提供,它沒有任何'xargs'欺騙。 – tripleee 2017-10-25 03:24:27

+0

@tripleee'find'不搜索文件內容,關鍵是隻處理匹配的文件而無需編寫Perl程序。 – Walf 2017-10-25 05:30:15

-3

找到&替換文件的vi模式 的語法如下: :%s/WORD找到的-HERE /替換詞,這裏/ G

OR :%s/FindMe/ReplaceME /克

實例

的替代命令可用於按您的要求。