如何使用反引号扩展来填充arglist?


11

来自帮助:help backtick-expansion

On Unix and a few other systems you can also use backticks for the file name
argument, for example:
    :next `find . -name ver\\*.c -print`
    :view `ls -t *.patch  \| head -n1`
The backslashes before the star are required to prevent the shell from
expanding "ver*.c" prior to execution of the find program.  The backslash
before the shell pipe symbol "|" prevents Vim from parsing it as command
termination.

如果键入从帮助中获取的命令,则会收到错误消息:

:next `find . -name ver\\*.c -print
E79: Cannot expand wildcards  

为什么帮助中的示例使用两个反斜杠而不是一个反斜杠,为什么它不起作用?

以下工作:

  • 如果我在find程序之前删除了两个反斜杠之一,它们可以防止星星被外壳扩展:

    :next `find . -name ver\*.c -print`
    
  • 如果删除两个反斜杠并在模式周围加上单引号ver*.c

    :next `find . -name 'ver*.c' -print`
    

到目前为止,规则似乎是:
如果shell命令中包含星号,并且您不希望shell在命令前将其展开,则在其前面加上一个反斜杠或在pattern周围加上单引号

但是帮助给出了另一个示例:

:view `ls -t *.patch  \| head -n1`

此命令无需任何修改即可工作,不需要单引号,也不需要反斜杠。
我想它起作用的原因是因为ls命令(与命令的-name参数相反find)接受多个文件参数,并且看到shell扩展没有问题*.patch

现在,让我们说,我想看看所有的文件扩展名为.conf内部/etc文件夹和管道输出find,以grep获得仅包含字符串匹配input
在外壳程序中,从任何工作目录中,我将输入:

find /etc -name '*.conf' | grep input

它会工作。

在vim中,我将键入相同的命令,在命令前后加上反引号,并在管道符号前加上反斜杠,以防止vim将其解释为命令终止:

:next `find /etc -name '*.conf' \| grep input`

而且有效。

现在,如果键入不带管道和的相同命令grep input,则会出现错误:

:next `find /etc -name '*.conf'`
E79: Cannot expand wildcards

即使我用单引号保护了星号,在这种情况下为什么也会出现错误?
并且为什么现在会出现错误,而不仅仅是在管道和之前出现错误grep input

为了理解,我想出了一个简单的命令:

find . -name '*.conf'

.conf在工作目录中查找所有带有扩展名的文件。该命令在外壳中有效。

为了在vim中进行测试,我输入了::next `find . -name '*.conf'`
并且它可以工作。在这种情况下,点代表我当前的工作目录,如Ex命令显示的那样,:pwd这是我的主目录,/home/username因为我从该目录启动了vim会话。

为什么当我要求在当前工作目录中进行搜索时它为什么起作用,而当我要求在任意文件夹中进行搜索时却不起作用/etc

现在,如果使用vim Ex命令将工作目录从更改/home/username/etc:cd /etc然后重试与以前相同的命令,则会再次出错:

:next `find . -name '*.conf'`
E79: Cannot expand wildcards

为什么当我位于主目录中时,相同的命令起作用,而当我处于目录中时,为什么不起作用/etc

我敢肯定有一些逻辑,但是我找不到。

用任意的shell命令(包含星号,管道,从任何工作目录中的任何目录中搜索)填充arglist的一般正确语法是什么?

我正在使用vim版本7.4.942,而zsh是我的默认shell。我用最少的vim -u NORC -Nbash和zsh 初始化()测试了这些命令。

我需要配置vim来调用bash而不是zsh吗?


我想知道您是否尝试使用所有作为参数传递的文件来启动vim?我的意思是:vim $(find . -name ver*.c)
Vlad GURDIGA

@VladGURDIGA我只是试着和他们从壳预期的所有工作:vim $(find . -name ver\*.c -print)vim $(ls -t *.patch | head -n1)vim $(find /etc -name '*.conf' | grep input)vim $(find /etc -name '*.conf')vim $(find . -name '*.conf')
萨吉诺

@VladGURDIGA但我想知道如何填充arglist而不退出当前会话,因为我通常只有一个会话。我也可以在shell中四处走动,搜索一组文件并将它们发送到Vim服务器(带有参数--remote,请参见:vi.stackexchange.com/a/5618/4939),但我很好奇如何知道直接在当前会话中执行此操作。如果不可能的话,但是在阅读了帮助之后,看来可以完成。如果是这样,我想理解为什么vim对类似命令的反应如此不同。
saginaw 2015年

嘿,似乎在第一个示例命令中,您缺少结束符。;)除此之外,我想帮助中的示例使用两个反斜杠而不是一个反斜杠来防止外壳扩展,如此处所述:unix.stackexchange.com/q/104260/23669
弗拉德·古迪加

find /etc -name '*.conf'不起作用的情况下,我认为该命令会产生一些有趣的名称,这可能是通过管道传递时起作用的原因grep
弗拉德·古迪加

Answers:


6

我仍然不知道如何使用backtick-expansion用任意的shell命令填充arglist,但是我找到了一种解决方法。

来自:help `=

You can have the backticks expanded as a Vim expression, instead of as an
external command, by putting an equal sign right after the first backtick,
e.g.:
    :e `=tempname()`
The expression can contain just about anything, thus this can also be used to
avoid the special meaning of '"', '|', '%' and '#'.  However, 'wildignore'
does apply like to other wildcards.

因此,与其直接展开这样的shell命令,不如:

:args `shell command`

我们可以将shell命令发送到Vim函数,systemlist()并使用表达式寄存器=来扩展结果表达式,如下所示:

:args `=systemlist("shell command")`

为了保存一些击键,我在vimrc中定义了以下Ex命令(:PA对于Populate Arglist):

command! -nargs=1 PA args `=systemlist(<q-args>)`

并使用各种shell命令对其进行了测试:

:PA find . -name ver\*.c -print 2>/dev/null
:PA find . -name 'ver*.c' -print 2>/dev/null
:PA ls -t *.patch  | head -n1
:PA find /etc -name '*.conf' 2>/dev/null | grep input
:PA find /etc -name '*.conf' 2>/dev/null
:PA find . -name '*.conf' 2>/dev/null

到目前为止,它的工作方式与预期的一样,并且可以像在shell中一样键入命令(例如,无需对管道进行转义)。
它似乎比直接反引号扩展更加一致和可靠。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.