在vim中访问本地shell变量

4

在vim中,我可以访问我的bash环境变量,例如$PWD和$PATH。我想知道如何在vim中访问临时shell变量。

例如,假设我在终端中定义一个变量foo="bar"。然后进入vim并尝试使用以下命令:!echo $foo访问此变量,但它无法识别此变量。据我所知,每次调用bash命令时,vim都会启动一个新的shell,然后立即关闭它。是否有一种方法可以在vim中使用与定义foo的本地变量相同的shell?


1
顺便说一句,我认为你想要的是“shell变量”(而不是“环境变量”);“局部变量”仅限于单个函数的执行范围,而不是限于运行它的shell。 - Charles Duffy
3个回答

6
不,您无法从子进程与生成它的父shell互动(除非该shell积极参与,这在手头的情况下不是合理/实际可行的)-但是您可以导出变量以使它们可供在子进程中启动的新shell访问。
运行
set -a

...将使得任何定义的变量自动导出到环境中,即使没有显式的export命令。


与C语言的system()函数不同,vim的system()函数会遵循SHELL环境变量。如果SHELL=/bin/bash(或在vim中运行了:set shell=/bin/bash),您还可以从vim中调用已导出的函数。也就是说,如果您按照以下方式定义并导出函数:

foo() { echo "bar"; }
export -f foo

如果你定义了foo函数,那么你可以在vim内部使用!foo来调用。

即使如此,这仍然在一个新的、短暂的shell实例中运行,而不是原始的父进程。


5

解释

环境变量和shell变量是两个完全不同的概念,但在bash中以类似的方式操作它们,很容易混淆。

  • 每当创建一个进程(通过fork),它可能包含一个环境,在fork时由其父进程给出。然后子进程可以访问和修改其内容。作为用户如何完成这个过程取决于程序:

    • 在vim中,您可以像这样访问环境变量:echo $foo
    • 在bash中,您可以像这样访问它:$ echo "$foo"
    • 在大多数编程语言中,您可以使用与语言的其余部分一致的语法访问它,例如在ruby中的ENV['foo']
  • 另一方面,程序可能会为任何内部使用分配内存,但特别是它经常定义和使用变量。再次,这取决于程序:

    • 在vim中,您将使用:let命令来分配内部变量
    • 在bash中,您将使用$ foo='bar'分配变量,然后使用$ echo "$foo"读取它
    • 在大多数编程语言中,您有一个foo='bar'语法的变化,有时带有类型声明等

正如您所看到的,bash 使用相同的语法来读取环境变量和其自己的私有变量,这可能会导致一些混淆。

当您从bash shell执行vim时,环境从父进程(bash)复制到子进程(vim),但是bash的私有内存(包括您可能定义的变量)不会被复制。

因此,从子进程访问它们需要一些进程间通信机制,在父进程和子进程之间。虽然在技术上可行,但bash和vim没有实现此选项。


解决方案

为了使您的变量可以从vim(或任何分叉进程)中访问,您需要将其存在于vim进程的环境中。

有几个选项:

  • $ export foo='bar' :这将标记您的变量以供随后执行的命令环境导出。在大多数情况下,这是您想要的。
  • $ foo='bar' vim :这将添加您的变量到 vim 命令的环境中。非常适用于故障排除或单行命令。
  • $ set -a :从bash manpage中可以看出,这将标记每个后续定义以便导出到后续命令的环境中。它本质上相当于在每个后续定义之前加上export

更进一步

  • 问题使用了:!echo $foo语法显示foo的值,这是另一个用例。这里的!实际上是一个转义序列,允许您从vim中执行一个shell命令。

    但是,vim无法在父shell(您执行vim命令的那个)中执行任何操作,因此它会在子进程中创建一个新的bash shell,在其中执行echo并显示结果。

    在当前情况下,结果大多相同,但在其他情况下可能很容易产生误导,因此了解此处发生的情况非常重要。

  • 另一种vim语法,使用expand,允许查找变量::echo expand("$foo")

    它的工作方式完全不同。

    如果不存在名为foo的内部变量,则vim将调用shell来查找它(类似于!会做的事情)。

    这个选项比环境查找慢得多,对于大多数用例而言不建议使用。


或者 :e ^R=expand($myprojectdir) 的意思是,当按下<c-r>时,您可以交互地展开变量以在ex中使用。 - MacMartin
或者 :e ^R=expand($myprojectdir) 的意思是,当按下<c-r>时,你可以交互地展开变量以在ex中使用。 - undefined

2
如果您想在:substitute命令中使用来自您的shell的值,实际上有一种方法可以做到。
我不知道它是否解决了您的需求,但我们来试试吧。
假设我们想用您的PWD替换Mydir
:s/Mydir/\=expand($PWD)/g

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接