交互式搜索并从shell中替换

时间:2011-06-28 07:06:56

标签: shell find replace

在我的编辑器中搜索和替换多个文件很困难。 findxargssed / awk包含多个文件中的搜索和替换,可以完成大量的操作。但不知何故,我找不到一种方法来实现这种互动。你知道这样做的方法吗?

8 个答案:

答案 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宏。第一个宏将执行替换命令,第二个宏将执行wn命令以保存更改并获取下一个文件。

在过去的30年里,我使用了这个(以及带有vi的旧版本)。特别是,当您将其中的两个部分编码为两个击键宏时,您可以非常快速地运行它,因为它很容易按住控制键,并反复输入几个字母,例如R Y.它比编写完全自动化的脚本所花费的时间更快,并且由于重现起来很简单,您可以在您正在使用的任何计算机上执行此操作。

答案 3 :(得分:1)

使用grep,xargs和vi / vim执行此操作的UNIX方法:

  1. 制作别名
  2. 当你想从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 $*'
    
    1. 执行搜索并检查文件列表
    2. 命令:

      ge -l 'foo' .
      
      1. 再次执行搜索,告诉vim以交互方式替换每个文件
      2. 命令:

        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

        优点:

        • 命令很容易取消:只是退出vim

        缺点:

        • 您必须依次切换到每个缓冲区并重新运行&#34;%s&#34;命令就可以了

        • 如果你有很多文件,这会让vim消耗大量的内存(有时候会像一个完整的IDE一样多!)

        b)依次为每个文件启动vim

        优点:

        • 一切都是自动化的。启动Vim并执行搜索命令

        • 内存亮起

        缺点:

        • 很难取消:退出vim会让xargs打开下一个

        我更喜欢变体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>)

备注

  • 正如我在此处制定的那样,它只搜索Subversion在版本控制下从当前目录递归的那些文件。根据您的需要,您可以根据需要对其进行概括或将其适用于不同的版本管理系统。
  • 使用的模式是搜索到的最后一个模式。如果您不喜欢这样,您可以再次满足您的需求。
  • Gsubstitute用于“全球替代”。您可以随意调用命令,但我喜欢这样,因为:Gs似乎符合Vim风格。
  • 如果你有大量的文件,这是一个很好的解决方案,因为它需要Vim的责任来全部搜索(即它也可能解决this guy's problem。)
  • 最后的do-nothing echo和传递给-s的{​​{1}}是为了掩盖grep遇到的错误。 grep提供非零返回码,即使它确实找到了良好的结果。

使用示例

grep

我喜欢使用以前的搜索模式的一个原因是它允许您通过将光标放在类上,执行 * #<来快速为类提供完全不同的名称/ kbd>,然后是你的/OldClassName :Gs NewClassName 命令,这样就不必输入整个搜索字符串。

答案 5 :(得分:0)

您可以尝试使用此工具在内部模式内查找和替换shell

https://sourceforge.net/projects/isartool/

不需要X服务器,如果你想在目录中使用-r选项递归它。

答案 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。