【问题标题】:egrep results to vim as a line referenced filelistegrep 结果到 vim 作为行引用的文件列表
【发布时间】:2012-07-27 17:29:08
【问题描述】:

在 shell 中,我使用以下函数创建文件列表并将其传递给 vim。

感觉不错,但我丢失了行引用,我以正确的顺序打开文件,但是当光标从第一行开始时,我必须再次搜索文本。

~/.bashrc 上的实际函数

function vimgrep(){
   vim `grep -IR "$1" * | awk -F: '$1!=f{print ""$1"";f=$1}' | grep -v 'Test\|test'` +ls
}

function vimgrep2(){
   vim `grep -IR "$1" * | awk -F: '$1!=f{print ""$1"";f=$1}' ` +ls
}

Obs.: filelist 必须来自 shell 到 vim,然后它必须保留缓冲文件的行引用,就像 :make 捕获任何错误时的结果一样(但没有底部窗口 [:cwindow] )。

编辑: 好的...不是那么优雅,但我可以将搜索到的字符串作为 +/"$1" 传递给 vim,例如:

   vim `grep -IR "$1" * | awk -F: '$1!=f{print ""$1"";f=$1}' ` +/"$1"

如果脚本不使用临时文件会更好。

【问题讨论】:

  • 在黑暗中拍摄,但您可以将行地址写入list_of_lines 并以-q list_of_lines 启动vim。

标签: bash shell vim grep


【解决方案1】:

Vim 还带有一个您可以使用的vimgrep 命令

function vimgrep() {
    local regex="$1"

    if [[ -z "$regex" ]]; then
        echo "Usage: $0 regex" 1>&2
        exit 1
    fi

    vim -c "vimgrep /$regex/ **"
}

小心运行它的目录下有很多文件。

【讨论】:

  • 行得通!谢谢,我只编辑了一点:vim -c "vimgrep /$regex/ **/*.h **/*.cpp"
  • 奇怪,但它不接受 *****/****.{h,cpp} 模式,但上面的工作原理!
【解决方案2】:

在外部 Grep 中使用行号

据我所知,不能使用行号选项标志一次打开多个文件,因为 Vim 只会将该标志应用于列表中的第一个文件。手册页说:

 +[num]      For the first file the cursor will be positioned on line  
             "num". If "num" is missing, the cursor will be positioned
             on the last line.

因此,您可以一次对每个文件调用一个函数,或者将函数调用放在一个循环中,该循环一次对两个位置参数(文件名和正则表达式)进行操作。前者当然更容易。例如:

vimgrep () {
    local file="$1"
    shift || return 1
    vim +$(egrep -n "$1" "$file" | cut -d: -f1) "$file"
}

# Sample function call.
vimgrep /etc/password '^www-data'

【讨论】:

  • 也许一种方法是在每一行上设置一个标记 m{a-zA-Z},但为此我们将超过 vim 使用 -c 作为参数的“最多 10 个 cmd”你+cmd。似乎这最终会得到一个临时的 golfy 文件脚本,每次调用 vimgrep 时都会创建和删除。
  • 其他是加载缓冲区必须像 :make 在出现问题时所做的那样。现在我正在搜索 -q 选项示例。
【解决方案3】:

有了这个你可以通过cncpcc..等在比赛之间移动:

function vimgrep(){
   vim -c "exec(\"grep $1 *\")"
}

带高亮:

function vimgrep(){
   vim -c "exec(\"grep -IR $1 *\")" -c "let @/='$1'" -c "set hls"
}

【讨论】:

  • @CodeGnome,您可以通过按nvisual mode 中的匹配项之间进行选择。
【解决方案4】:

免责声明:我对@9​​87654321@一无所知

手册页使用+<line no> 之类的参数表示,它将跳转到所提供文件的该行。根据这些信息,我编写了这个脚本。它依赖于如下命令行来启动 vim:

$ vim +n1 file1 +n2 file2

你也可以把它作为一个shell函数放在你的'~/.bashrc中,因为它很小。

用法:vimgrep -e <search pattern> <fileglob>

搜索模式可以是grep能理解的任何正则表达式,文件glob是bash能理解的shell glob。

#!/bin/bash

# set -o xtrace # uncomment to debug

# declare variables
declare -a grepopts files

[[ $1 =~ -e$ ]] && grepopts+=("-e") && grepopts+=("$2") && shift 2

files=("${@}")

vim $(egrep -n -m1 -H "${grepopts[@]}" "${files[@]}" | \
        sed -e 's/^\(.\+\):\([0-9]\+\):.\+$/+\2 \1/')

警告:如果文件名中包含 : 字符,此脚本将失败。

【讨论】:

  • 用那个 bashrc 不会是 Usage vim -e ?
  • @RodrigoGurgel 抱歉,我不关注您的评论。我的用法是基于您在问题中将示例函数命名为 vimgrep 的事实。它应该是你给脚本或 shell 函数起的名字;在 bash 变量中:$0 -e <pattern> <fileglob>。 PS:我刚刚用更多的 cmets 编辑了答案
  • @RodrigoGurgel 你想让函数/脚本一次打开所有文件吗?比如,用match打开file1,你做一些事情,:q,用match打开file2,做一些事情,:q,等等?
  • 文件将被缓存在一个列表中,可以通过:ls访问,就像当你执行"vim text1.txt text2.txt"时,当执行vim内部的:ls时会出现一个列表对于缓冲文件,vim 将从列表的第一个文件开始,然后您可以使用 :next 导航,但是当我们这样做时,光标总是转到第 1 行,而不是 grep 行(模式匹配的地方)。
  • 我不知道怎么做,但是当你做 :make 并导致错误时,vim 可以保存对文件 + 行的引用,你可以在其中导航 :cnext :cp :cwindow
【解决方案5】:

这里有一些功能可以为您提供您想要的。它将打开缓冲区中的每个文件,并将行设置为与给定正则表达式匹配的第一行。

我倾向于喜欢这样简短的描述性 bash 函数,因为不使用大量代码块就很难理解 bash。

唯一的缺陷是它不能有效地过滤掉二进制文件。 find_nonbinary 函数的更新将解决此问题。

这些是辅助函数。它们不能直接运行。

# Using print0 to handle files with weird names.
# This is just a quick placeholder.
# You can play with this to get better results.
function __find_nonbinary() {
    find -type f -print0
}

function __generate_vim_cmds() {
    xargs -0 awk -v regex="$regex" \
        '$0 ~ regex {printf "e +%s %s\n", FNR, FILENAME; nextfile}'
}

function __combine_vim_cmds() {
    declare -a vim_cmds

    while read line; do
        vim_cmds+=( " $line " )
    done

    # Force subshell to prevent IFS from being clobbered.
    (
        IFS="|"
        echo "${vim_cmds[*]}"
    )
}

这是要使用的实际功能。

function vimgrep() {
    local regex="$1"

    if [[ -z "$regex" ]]; then
        echo "Usage: $0 regex" 1>&2
        exit 1
    fi

    local vim_cmds=$(
        __find_nonbinary    |
        __generate_vim_cmds |
        __combine_vim_cmds
    )

    if [[ -z "$vim_cmds" ]]; then
        echo "No files matching $regex found." 1>&2
        exit 1
    fi

    vim -c "$vim_cmds"
}

【讨论】:

  • 查找结果为:./TestMaxFoo./foo./TestFooMessage./Test,最后我的 ps1 出现在同一行 <...>./TestFooCenter.o./TestFooMetrics.o
  • 使用第二个 cmd 结果为: e +1 ./TestMaxFooSize e +1 ./foo e +1 ./TestFooMessage
  • @Rodrigo:您不应该手动运行这些函数。它们在下面的 vimgrep 函数中使用。
  • 我这样做是为了调试 =D,让你看看发生了什么
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多