【问题标题】:How to do search & replace with ack in vim?如何在vim中用ack进行搜索和替换?
【发布时间】:2011-06-15 02:54:29
【问题描述】:

我在 Vim 中使用 Ack 插件,它可以帮助我在项目中快速搜索字符串。但是,有时我想替换所有或部分找到的字符串。您可以像这样使用 Vim arglist 进行某种全局搜索和替换 (source) :

:args app/views/*/*
:argdo %s/, :expire.*)/)/ge | update

但不是使用args,我更愿意通过 Ack 进行搜索,然后在找到的所有文件中进行替换。有没有类似于argdo 命令的方法?

【问题讨论】:

    标签: search vim replace ack


    【解决方案1】:

    我决定使用ackperl 在Vim 之外解决这个问题,这样我就可以使用更强大的Perl 正则表达式而不是GNU 子集。您可以将其映射到您的.vimrc 中的一个击键。

    ack -l 'pattern' | xargs perl -pi -E 's/pattern/replacement/g'
    

    说明

    ack

    ack 是一个很棒的命令行工具,它混合了grepfind 和完整的 Perl 正则表达式(不仅仅是 GNU 子集)。它是用纯 Perl 编写的,速度快,具有匹配突出显示功能,可以在 Windows 上运行,并且比传统的命令行工具对程序员更友好。使用 sudo apt-get install ack-grep 在 Ubuntu 上安装它。

    xargs

    xargs 是一个旧的 Unix 命令行工具。它从标准输入读取项目并执行指定的命令,然后执行为标准输入读取的项目。所以基本上ack 生成的文件列表被附加到perl -pi -E 's/pattern/replacement/g' 命令的末尾。

    perl -pi -E

    Perl 是一种编程语言。

    -p 选项使 Perl 围绕您的程序创建一个循环,该循环遍历文件名参数。

    -i 选项使 Perl 编辑文件。您可以修改它以创建备份。

    -E 选项使 Perl 执行指定为程序的一行代码。在我们的例子中,该程序只是一个 Perl 正则表达式替换。

    有关 Perl 命令行选项的更多信息,请参阅perldoc perlrun。有关 Perl 的更多信息,请参阅http://www.perl.org/

    【讨论】:

    • +1 由于没有安装 perl,我稍微使用了 sed 的解决方案:ack -l OLD_TEXT | xargs sed -i "" "s/OLD_TEXT/NEW_TEXT/g
    • @Eric Johnson,你为什么在这里使用-E 切换perl?我看不到任何功能的用处
    • @sputnick,我只是习惯性地使用 -E,所以我有“说”可用。 -e 当然也可以。
    • 这会给我带来错误,除非我告诉 ack 只列出带有 -l 的文件,如下所示:ack -l 'pattern' | xargs perl -pi -E 's/pattern/replacement/g'
    • @tommychheng 在没有 perl 的情况下如何运行 ack?
    【解决方案2】:

    现在,Vim 有了这个新命令 cdo,它将对快速修复列表的每一行运行给定的命令。

    所以你可以使用

    :Ack pattern
    :cdo s/pattern/newpattern/g
    

    【讨论】:

    • 这应该是公认的答案。效果很好,谢谢!
    • 从 vim 7.4 开始,这是正确的答案。对于 OP,稍作调整, :cfdo 可能更合适。
    • 我可能遗漏了一些明显的东西,但我在 Fedora 上运行 Vim 7.4,每当我尝试 :cdo 时,我都会收到 not and editor command,有什么想法吗?
    • 从帮助页面中,您需要使用+listcmds 功能编译您的vim。它是否解释了缺少的命令?
    • :cdo s/pattern/newpattern/g | update 为我工作。
    【解决方案3】:

    我不相信有一种内置的方法可以做到这一点,但应该很容易做到。

    您需要做的是创建一个调用自定义函数的命令。然后该函数应该使用getqflist() 函数来获取快速修复列表中的所有条目,并使用exe 来完成脏活。小心你作为参数传递的内容!

    " Define a command to make it easier to use
    command! -nargs=+ QFDo call QFDo(<q-args>)
    
    " Function that does the work
    function! QFDo(command)
        " Create a dictionary so that we can
        " get the list of buffers rather than the
        " list of lines in buffers (easy way
        " to get unique entries)
        let buffer_numbers = {}
        " For each entry, use the buffer number as 
        " a dictionary key (won't get repeats)
        for fixlist_entry in getqflist()
            let buffer_numbers[fixlist_entry['bufnr']] = 1
        endfor
        " Make it into a list as it seems cleaner
        let buffer_number_list = keys(buffer_numbers)
    
        " For each buffer
        for num in buffer_number_list
            " Select the buffer
            exe 'buffer' num
            " Run the command that's passed as an argument
            exe a:command
            " Save if necessary
            update
        endfor
    endfunction
    

    【讨论】:

    • 假设您执行:QFDo v/skipPat/s/Pat/Rep/gce 之类的操作,并且在 quickfix 窗口中有大量缓冲区。然后在第一个文件中,您注意到您输入了替换字符串 Rep。输入 Ctrl-c 不会停止命令,而只会停止当前行上的替换命令 - 对于每个缓冲区上匹配的每一行,都需要一个 Ctrl-c。有什么技巧可以抓住Ctrl-cESC 键并打破上面函数的for 语句?
    • 根据上面的答案另见this article,它起源于this plugin
    【解决方案4】:

    你可以通过这种方式使用 ack

    :args `ack -l User app/`
    :argdo %s/, :expire.*)/)/ge | update
    

    或者使用 ag

    :args `ag -l User app/`
    :argdo %s/, :expire.*)/)/gec | w
    

    【讨论】:

      【解决方案5】:

      我使用 MacVim(在 shell 中使用 mvim 激活)。我将ack 的结果通过管道传输到mvim

      mvim -f $(ack -l $@)
      

      然后在 MacVim 中,我使用 bufdo 搜索/替换:

      :bufdo %s/SEARCH/REPLACE/gce | update
      

      如果不需要确认,请省略c 选项。

      【讨论】:

      • 做 vim -p $(ack -Qil "string to match") 让这些在单独的标签中启动(如果这是你的事!)
      猜你喜欢
      • 2011-11-02
      • 2015-02-15
      • 2016-07-12
      • 2017-09-21
      • 1970-01-01
      • 1970-01-01
      • 2017-01-05
      • 1970-01-01
      • 2015-05-02
      相关资源
      最近更新 更多