【问题标题】:Access local shell variables in vim在 vim 中访问本地 shell 变量
【发布时间】:2018-10-25 19:11:13
【问题描述】:

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

例如,假设我在终端中定义了一个变量foo="bar"。然后我进入vim,尝试用下面的命令:!echo $foo访问这个变量,但是它不识别这个变量。据我了解,vim 每次调用 bash 命令时都会启动一个新的 shell,然后立即关闭它。有没有办法在 vim 中使用与我的局部变量 foo 定义相同的 shell?

【问题讨论】:

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

标签: bash vim


【解决方案1】:

说明

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

  • 无论何时(通过 fork)创建一个进程,它都可能包含一个环境,由其父进程在 fork 时提供。然后子进程可以访问和修改其内容。作为用户如何做到这一点取决于程序:

    • 在vim中,你可以access an environment variable这样::echo $foo
    • 在 bash 中,您可以像这样访问它:$ echo "$foo"
    • 在大多数编程语言中,您可以使用与其他语言一致的语法来访问它,例如 ruby​​ 中的 ENV['foo']
  • 另一方面,程序可以为任何内部使用分配内存,但值得注意的是,它经常会定义和使用变量。再一次,这取决于程序:

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

如您所见,bash 使用相同的语法来读取环境变量和它自己的私有变量之一,这可能会导致一些混乱。

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

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


解决方案

为了让您的变量可以从 vim(或任何派生进程,就此而言)访问,您需要它存在于您的 vim 进程的环境中。

有几种选择:

  • $ export foo='bar' :这将标记您的变量以导出到随后执行的命令的环境中。在大多数情况下,这就是您想要的。
  • $ foo='bar' vim :这会将您的变量添加到 this vim 命令的环境中。对于故障排除或单线非常有用。
  • $ set -a :正如您在bash manpage 中看到的,这标记了每个后续定义以导出到后续命令的环境。这基本上相当于在每个后续定义前面加上export

走得更远

  • 该问题使用:!echo $foo 语法来显示foo 的值,这是另一个用例。这里的!实际上是一个转义序列,可以让你从vim执行一个shell命令。

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

    在当前情况下,结果基本相同,但在其他情况下很容易产生误导,因此了解这里发生的情况很重要。

  • another vim syntax,使用expand,允许查找变量::echo expand("$foo")

    但它的工作方式完全不同。

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

    此选项方式比环境查找慢,不推荐用于大多数用例。

【讨论】:

    【解决方案2】:

    不,您不能从它生成的子进程与父 shell 交互(没有该 shell 的积极参与,这在手头的场景中是不合理/实际可用的)——但是您可以 导出您的变量,以使在子进程中启动的新 shell 可以访问它们。

    跑步

    set -a
    

    ...即使没有明确的export 命令,也会自动将定义的任何变量导出到环境中。


    由于(与 C 中的 system() 函数不同)vim 的 system() 尊重 SHELL 环境变量,如果 SHELL=/bin/bash(或 :set shell=/bin/bash 已在 vim 中运行),您还可以从 vim 调用导出的函数。也就是说,如果你定义函数并导出它如下:

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

    ...然后您可以在 vim 中使用 !foo 调用它。

    然而,即便如此,它还是在一个新的、临时的 shell 实例中运行,而不是在原来的父进程中。

    【讨论】:

      【解决方案3】:

      如果您想在 :substitute 命令上使用 shell 中的值,实际上有一种方法可以做到。

      我不知道它是否能解决您的需求,但我们开始吧。

      假设我们想用您的PWD 替换Mydir

      :s/Mydir/\=expand($PWD)/g
      

      【讨论】:

        猜你喜欢
        • 2018-08-10
        • 2017-10-14
        • 2011-10-21
        • 2011-04-26
        • 1970-01-01
        • 2020-05-01
        • 2016-05-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多