在我的编辑器中搜索和替换多个文件很困难。 find
,xargs
和sed
/ awk
包含多个文件中的搜索和替换,可以完成大量的操作。但不知何故,我找不到一种方法来实现这种互动。你知道这样做的方法吗?
答案 0 :(得分:6)
KISS原则:
vim
:args `ls`
:argdo %s#SEARCH#REPLACE#gec |update
%s后的第一个字符用作分隔符
答案 1 :(得分:3)
我会将这些修改添加到狄龙的答案中:
-le
选项应添加到grep
命令。
vim `find . -name '*.c' -exec grep -le '\<junk\>' {} \;`
然后你在Vim,但你没有机会选择要替换的内容,最后在交互式替换时添加c
选项,在开头添加bufdo
以遍历每个文件:
:bufdo %s/junk/rubbish/gce
稍后您保存所有工作:
:bufdo wq!
答案 2 :(得分:1)
只需使用Vim。
首先使用find来列出所有需要更改的文件。
vim `find . -name '*.c' -exec grep junk {} \;`
使用包含字符串.c
的所有junk
文件启动vim。现在,在vim中对第一个文件进行更改:
:%s/junk/rubbish/g
然后输入: w 输入 : n 输入用于下一个文件。
现在您需要重复编辑过程。如果它只是一个替换命令而只是几个文件,则键入: Up 输入以重复替换命令。
但是如果有很多,你应该使用map
来创建几个kestroke宏。第一个宏将执行替换命令,第二个宏将执行w
和n
命令以保存更改并获取下一个文件。
在过去的30年里,我使用了这个(以及带有vi的旧版本)。特别是,当您将其中的两个部分编码为两个击键宏时,您可以非常快速地运行它,因为它很容易按住控制键,并反复输入几个字母,例如R Y.它比编写完全自动化的脚本所花费的时间更快,并且由于重现起来很简单,您可以在您正在使用的任何计算机上执行此操作。
答案 3 :(得分:1)
使用grep,xargs和vi / vim执行此操作的UNIX方法:
当你想从grep中排除某些东西时,这将有助于避免长命令。
alias ge='grep --exclude=tags --exclude=TAGS --exclude-dir=.git --exclude-dir=build --exclude-dir=Build --exclude-dir=classes --exclude-dir=target--exclude-dir=Libraries --exclude=*.log --exclude=*~ --exclude=*.min.js -rOInE $*'
命令:
ge -l 'foo' .
命令:
ge -l 'foo' . | xargs -L 1 -o vim -c '%s/foo/bar/gc'
命令说明:
直到管道的部分是重复的搜索命令
在管道之后,我们调用xargs在每个文件上启动vim
&#34; -L 1&#34;告诉xargs在每一行上启动命令,而不是在一个命令中组合所有行。如果您希望一次性对所有文件启动vim,请删除&#34; -L 1&#34;来自xargs。
&#34; -o&#34;告诉xargs使用实际终端而不是/ dev / null
此命令有两个选项:
a)立即对所有文件启动vim
优点:
缺点:
您必须依次切换到每个缓冲区并重新运行&#34;%s&#34;命令就可以了
如果你有很多文件,这会让vim消耗大量的内存(有时候会像一个完整的IDE一样多!)
b)依次为每个文件启动vim
优点:
一切都是自动化的。启动Vim并执行搜索命令
内存亮起
缺点:
我更喜欢变体b),因为它是自动的,更像UNIX。仔细规划 - 首先检查文件列表,并在子目录上运行命令以缩小范围 - 使用它非常好。
一般优势:
可以使用几乎在每个平台上都可用的标准UNIX工具来实现
很高兴使用
一般缺点:
您必须输入两次搜索表达式
您可能会遇到复杂搜索/替换表达式上的bash转义问题
答案 4 :(得分:0)
如果您发现经常要这样做,或者您只想在版本控制下搜索文件,这是@jhvaras答案的增强。
function SvnProjectSubstitute(replacement)
execute "args `grep -sl '" . @/ . "' $(svn --recursive list)`; echo -n ''"
argdo execute "substitute//" . a:replacement . "/gc"
endfunction
command -nargs=1 -complete=file Gsubstitute call SvnProjectSubstitute(<f-args>)
备注强>:
Gsubstitute
用于“全球替代”。您可以随意调用命令,但我喜欢这样,因为:Gs
似乎符合Vim风格。-s
的{{1}}是为了掩盖grep
遇到的错误。 grep
提供非零返回码,即使它确实找到了良好的结果。使用示例:
grep
我喜欢使用以前的搜索模式的一个原因是它允许您通过将光标放在类上,执行 * 或#<来快速为类提供完全不同的名称/ kbd>,然后是你的/OldClassName
:Gs NewClassName
命令,这样就不必输入整个搜索字符串。
答案 5 :(得分:0)
答案 6 :(得分:0)
我无法获得马里奥的工作答案,但如果我使用xargs就行了。
此外,大多数时候我想在多个文件中进行搜索和替换,我想将一个字母数字ID从一个东西更改为另一个东西,例如重命名变量或类等。为此,它&#39;在你替换之前或之后添加一个负面的lookbehind和负向前导以禁止单词字符是非常有帮助的,并且因为grep需要P标志来使用Perl正则表达式:
vim `find . -name '*.cpp' -o -name '*.hpp' | xargs grep -Ple '(?<!\w)FIND(?!\w)'`
:bufdo %s/FIND/REPLACE/gce
当然,将它包装在脚本中是有帮助的,这样您就不必每次都重新输入它。这是一个开始:
#!/bin/bash
if [[ $# < 2 ]]; then
echo "Usage: search-replace <search> <replace>"
exit 1
fi
search="$1"
replace="$2"
files=`find . -name '*.cpp' -o -name '*.hpp' | xargs grep -Ple "(?<!\w)$search(?!\w)"`
if [[ -z "$files" ]]; then
echo "No matching .cpp or .hpp files."
exit 1
fi
# The stuff surrounding $search is the negative lookahead/lookbehind
vim -c "set hidden | bufdo %s/\(\w\)\@<!$search\(\w\)\@!/$replace/gce" $files
对于我来说,使用Mario的解决方案仍然无法正常工作的东西是在第一个文件的末尾它说:
Error detected while processing command line:
E37: No write since last change (add ! to override)
这可以防止搜索和替换流向下一个文件。似乎&#34;设置隐藏&#34;解决了这个问题,所以我在上面的脚本中使用了它。
剩下的一个问题是,在第一个文件上执行搜索和替换后,它似乎第二次处理第一个文件,撤消初始替换。如果有人知道为什么会这样,请告诉我。
答案 7 :(得分:0)
从jhvaras的答案中,我做出了这个bash命令来快速搜索和替换(添加到.bashrc
中):
replace () {
if [ $# -lt 2 ]
then
echo "Recursive, interactive text replacement"
echo "Usage: replace text replacement"
return
fi
vim -u NONE -c ":execute ':argdo %s/$1/$2/gc | update' | :q" $(ag $1 -l)
}
它的用法如下:
~$ replace some_text some_new_text
它使用ag
进行预先搜索,因为它可能比让vim
进行工作要快,但是您可以用其他任何东西代替。它还调用无插件的vim
以达到最大速度,完成所有替换后,它将自动退出并返回Shell。