2

我编写了一个函数,可以在 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"
4

2 回答 2

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[@]}"(带有 the@和双引号)会将数组扩展为元素列表。
该表单"${array[*]}"会将数组扩展为单个字符串。

于 2013-05-24T12:31:43.280 回答
0

您遇到的第一个问题是 args 在 while 循环之外没有更新。因此,您应该只使用重定向,而不是在 find 中使用管道。

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)

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

(这对您来说似乎不是问题,但如果不更改它,我无法让您的脚本正常工作)


可以通过更改行来解决字符串中引号过多的下一个问题

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

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

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

编辑更强大的解决方案是Ignacio Vazquex-Abrams 答案,但在适当的地方加上引号。


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

于 2013-05-24T03:34:40.973 回答