我正在尝试在 grep 匹配的所有文件中搜索和替换字符串:
grep -n 'foo' *
将以以下形式给我输出:
[filename]:[line number]:[text]
对于 grep 返回的每个文件,我想通过替换为来修改foo
文件bar
。
This appears to be what you want, based on the example you gave:
sed -i 's/foo/bar/g' *
It is not recursive (it will not descend into subdirectories). For a nice solution replacing in selected files throughout a tree I would use find:
find . -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;
The *.html
is the expression that files must match, the .bak
after the -i
makes a copy of the original file, with a .bak extension (it can be any extension you like) and the g
at the end of the sed expression tells sed to replace multiple copies on one line (rather than only the first one). The -print
to find is a convenience to show which files were being matched. All this depends on the exact versions of these tools on your system.
您的意思是在所有与 grep 匹配的文件中搜索并替换字符串?
perl -p -i -e 's/oldstring/newstring/g' `grep -ril searchpattern *`
编辑
因为这似乎是一个相当受欢迎的问题,所以我想更新一下。
现在我主要使用ack-grep
它,因为它更加用户友好。所以上面的命令是:
perl -p -i -e 's/old/new/g' `ack -l searchpattern`
要处理文件名中的空格,您可以运行:
ack --print0 -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'
你可以做更多的事情ack-grep
。假设您只想将搜索限制为 HTML 文件:
ack --print0 --html -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'
如果空白不是问题,它甚至更短:
perl -p -i -e 's/old/new/g' `ack -l --html searchpattern`
perl -p -i -e 's/old/new/g' `ack -f --html` # will match all html files
If your sed(1)
has a -i
option, then use it like this:
for i in *; do
sed -i 's/foo/bar/' $i
done
If not, there are several ways variations on the following depending on which language you want to play with:
ruby -i.bak -pe 'sub(%r{foo}, 'bar')' *
perl -pi.bak -e 's/foo/bar/' *
I like and used the above solution or a system wide search and replace among thousands of files:
find -name '*.htm?' -print -exec sed -i.bak 's/foo/bar/g' {} \;
I assume with the '*.htm?' instead of .html it searches and finds .htm and .html files alike.
I replace the .bak with the more system wide used tilde (~) to make clean up of backup files easier.
This works using grep without needing to use perl or find.
grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @
find . -type f -print0 | xargs -0 <sed/perl/ruby cmd>
will process multiple space contained file names at once loading one interpreter per batch. Much faster.
The answer already given of using find and sed
find -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;
is probably the standard answer. Or you could use perl -pi -e s/foo/bar/g'
instead of the sed
command.
For most quick uses, you may find the command rpl is easier to remember. Here is replacement (foo -> bar), recursively on all files in the current directory:
rpl -R foo bar .
It's not available by default on most Linux distros but is quick to install (apt-get install rpl
or similar).
However, for tougher jobs that involve regular expressions and back substitution, or file renames as well as search-and-replace, the most general and powerful tool I'm aware of is repren, a small Python script I wrote a while back for some thornier renaming and refactoring tasks. The reasons you might prefer it are:
Check the README for examples.
This is actually easier than it seems.
grep -Rl 'foo' ./ | xargs -n 1 -I % sh -c "ls %; sed -i 's/foo/bar/g' %";
Easy peasy. If you get a good grasp on find, grep, xargs, sed, and awk, almost nothing is impossible when it comes to text file manipulation in bash :)
2022 answer.
https://github.com/BurntSushi/ripgrep/blob/master/FAQ.md#how-can-i-search-and-replace-with-ripgrep
rg foo --files-with-matches | xargs sed -i 's/foo/bar/g'
will replace all instances of 'foo' with 'bar' in the files in which ripgrep finds the foo pattern. The -i flag to sed indicates that you are editing files in place, and s/foo/bar/g says that you are performing a substitution of the pattern foo for bar, and that you are doing this substitution globally (all occurrences of the pattern in each file).