如何用vim打开`find`输出?

时间:2013-05-24 02:05:14

标签: bash shell vim

我编写了一个函数,可以在Python文件中找到函数或类定义。它生成一个与vim一起使用的参数列表。它适用于第一个参数/文件,但后续文件失败,因为尾随“被添加到文件名。

尽管生成了正确的输出,但是当传递给vim时它不起作用。但是,当在命令行复制并粘贴相同的输出时,它可以工作。问题是,当它应该是命令字符串的结束时,结束"将被解析为文件名的一部分:

vim +cmd1 file1 +"file2_cmd file2_cmd file2" +"file3_cmd file3_cmd file3"

我需要在添加命令时添加文字双引号(\")的函数,但在与vim一起使用时解析文字引号。奇怪的是第一个文字引用被解析但不是最终文字引用。

vim +cmd file1 +" <-- this quote works, but this one doesn't --> "

代码:

function vpfd {
    local args=''

    find . -name "*.py" \
        | xargs grep -En "(def|class) ${@}[(:]" \
        | uniq \
        | while read line; do
              name=$(echo "${line}" | awk 'BEGIN { FS=":" }; { print $1 }')
              num=$(echo "${line}" | awk 'BEGIN { FS=":" }; { print $2 }')
              if [ ! "${args}" ]; then
                  args="+${num} ${name}"
              else
                  args+=" +\"tabnew +${num} ${name}\""
              fi
          done

    if [ "${args}" ]; then
        echo "vim ${args}"
        read p
        vim $(echo ${args})
    fi

示例:

$ vpfd main
vim +33 ./bar.py +"tabnew +15 ./foo.py"

如果我复制并粘贴上面一行就可以了,但是当函数试图打开vim并将其传递给${args}时,它不起作用。

在vim中:

  • 错误消息:Vim: not an editor command: 33 ./bar.py +"tabnew +15 ./foo.py"
  • 只显示空文件
  • 我退出空文件
  • vim然后在正确的行打开./bar.py,在第二个标签上打开错误的文件./foo.py"(尾随"

如果我复制并粘贴输出行,那么它可以正常工作:

$ vim +33 ./bar.py +"tabnew +15 ./foo.py"

2 个答案:

答案 0 :(得分:1)

这就是你需要的:

function vpfd {
    local args=() name num

    # in bash, putting a while loop in a pipeline implies the loop
    # runs in a subshell, thus when the subshell exits you will lose
    # any variable modifications.
    # Have the while loop read from a process substitution instead.

    # The read command can store multiple values, given the appropriate
    # field separator

    while IFS=: read -r name num; do
        if (( ${#args[@]} == 0 )); then
            args=( "+$num" "$name" )
        else
            args+=( +"tabnew +$num $name")
        fi
    done < <(
        find . -name "*.py" |
        xargs grep -En "(def|class) ${@}[(:]" |
        uniq
    )

    if (( ${#args[@]} > 0 )); then
        echo "${args[*]}"
        read -p "hit enter to continue" x
        vim "${args[@]}"
    fi
}

表单"${array[@]}"(带有@和双引号)会将数组扩展为其元素列表。
表单"${array[*]}"会将数组扩展为单个字符串。

答案 1 :(得分:0)

你遇到的第一个问题是args不会在while循环之外更新。因此,不应在查找中使用管道,而应使用重定向。

while read line; do
      name=$(echo "${line}" | awk 'BEGIN { FS=":" }; { print $1 }')
      num=$(echo "${line}" | awk 'BEGIN { FS=":" }; { print $2 }')
      if [ ! "${args}" ]; then
          args="+${num} ${name}"
      else
          args+=" +\"tabnew +${num} ${name}\""
      fi
  done < <(find . -name "*.py" | xargs grep -En "(def|class) ${@}[(:]" | uniq)

这允许args变量在while循环之外更新。

(这对您来说似乎不是问题,但我无法在不更改此情况的情况下使您的脚本正常工作)


可以通过更改行

来修复字符串中引号过多的下一个问题
args+=" +\"tabnew +${num} ${name}\""

args+=" +\"tabnew +${num} ${name}"

但我不确定这是一个强有力的解决方案。

修改更强大的解决方案是Ignacio Vazquex-Abrams Answer,除非在适当的位置加上引号。


您将遇到的最后一个问题是vim只接受十个+命令。因此,请确保您的脚本说明了这一点。