set、export 和 env 之间有什么区别,我应该什么时候使用它们?

Oli*_*Oli 144 command-line bash

每隔一段时间,我就会敲出一个 bash 脚本,它让我觉得有几种设置变量的方法:

key=value
env key=value
export key=value
Run Code Online (Sandbox Code Playgroud)

当您在脚本或单个命令中时(例如,我经常将变量与 Wine 启动器链接起来以设置正确的 Wine 前缀),这些似乎是完全可以互换的,但肯定不是这种情况。

这三种方法有什么区别,你能举个例子说明我什么时候特别想使用每种方法吗?

肯定与`VAR=...` 和 `export VAR=...` 有什么区别?但我也想知道如何env适应这个,一些展示每个好处的例子也很好:)

Jan*_*ary 135

让我们考虑一个具体的例子。该grep命令使用一个名为的环境变量GREP_OPTIONS来设置默认选项。

现在。鉴于该文件test.txt包含以下几行:

line one
line two
Run Code Online (Sandbox Code Playgroud)

运行命令grep one test.txt将返回

line one
Run Code Online (Sandbox Code Playgroud)

如果您使用该-v选项运行 grep ,它将返回不匹配的行,因此输出将是

line two
Run Code Online (Sandbox Code Playgroud)

我们现在将尝试使用环境变量设置选项。

  1. 没有export设置的环境变量不会在您调用的命令的环境中被继承。

    GREP_OPTIONS='-v'
    grep one test.txt
    
    Run Code Online (Sandbox Code Playgroud)

    结果:

    line one
    
    Run Code Online (Sandbox Code Playgroud)

    显然,该选项-v没有传递给grep

    当您设置一个仅供 shell 使用的变量时,您希望使用这种形式,例如在for i in * ; do您不想导出$i.

  2. 但是,该变量会传递到该特定命令行的环境中,因此您可以执行

    GREP_OPTIONS='-v' grep one test.txt
    
    Run Code Online (Sandbox Code Playgroud)

    这将返回预期

    line two
    
    Run Code Online (Sandbox Code Playgroud)

    您可以使用此表单临时更改已启动程序的此特定实例的环境。

  3. 导出变量会导致该变量被继承:

    export GREP_OPTIONS='-v'
    grep one test.txt
    
    Run Code Online (Sandbox Code Playgroud)

    现在返回

    line two
    
    Run Code Online (Sandbox Code Playgroud)

    这是在 shell 中设置变量以使用随后启动的进程的最常见方法

  4. 这一切都是在 bash 中完成的。export是一个内置的 bash;VAR=whatever是 bash 语法。env另一方面,它本身就是一个程序。当env被调用时,会发生以下事情:

    1. 该命令env作为新进程执行
    2. env 改变环境,和
    3. 调用作为参数提供的命令。该env过程由替换command过程。

    示例

    env GREP_OPTIONS='-v' grep one test.txt
    
    Run Code Online (Sandbox Code Playgroud)

    此命令将启动两个新进程:(i) env 和 (ii) grep(实际上,第二个进程将替换第一个进程)。从grep过程来看,结果和running完全一样

    GREP_OPTIONS='-v' grep one test.txt
    
    Run Code Online (Sandbox Code Playgroud)

    但是,如果您不在 bash 中或不想启动另一个 shell(例如,当您使用exec()函数系列而不是system()调用时),则可以使用此习惯用法。

附加说明 #!/usr/bin/env

这也是为什么使用习语#!/usr/bin/env interpreter而不是#!/usr/bin/interpreter. env不需要程序的完整路径,因为它使用execvp()函数搜索PATH变量,就像 shell 一样,然后 命令 run替换自身。因此,它可用于找出解释器(如 perl 或 python)在路径上的“位置”。

这也意味着通过修改当前路径,您可以影响将调用哪个 python 变体。这使得以下成为可能:

echo -e '#!/usr/bin/bash\n\necho I am an evil interpreter!' > python
chmod a+x ./python
export PATH=.
python
Run Code Online (Sandbox Code Playgroud)

而不是运行 Python,将导致

I am an evil interpreter!
Run Code Online (Sandbox Code Playgroud)

  • `set var=blah` 怎么样? (13认同)
  • 我认为你应该强调 `env` 也不会影响当前的 shell 环境变量(`env` 更改新进程中的环境变量)。我看了另一篇文章并自己澄清了这一点。 (4认同)
  • 为什么 GREP_OPTIONS='-v' grep one test.txt 有效?我认为它需要在“-v”后面加一个分号(但我尝试过,它确实有效。) (3认同)
  • 因为用分号,它被解释为两个单独的 bash 命令;第一个设置变量(不导出它),第二个从没有导出变量的环境开始。但是,如果没有分号,这只是一个命令 (grep),前面是设置本地环境。 (3认同)