接受还是不接受


32

命令之间有什么区别

$ env FOO=bar baz

$ FOO=bar baz

有什么作用env


4
这是一个附带的问题,但是当您为单个子命令设置环境变量时,该功能本身称为什么呢?我一直很难找到有关此信息,因为我不知道它叫什么。
约翰·克罗马蒂

1
@JohnCromartie,您应该提一个问题。
cjm 2014年

1
对于bash,它记录在这里:gnu.org/software/bash/manual/...
格伦·杰克曼

2
@JohnCromartie它是每个Shell命令的可选组件,因此它在大多数Shell手册的“简单命令”部分中。对于POSIX,将在此处。glenn已经为您链接了bash手册中的类似部分。
jw013

设置通过赋值不存在的变量将创建一个shell变量。通过ENV设置或导出变量会将变量推入Shell的执行环境。更改现有变量的值将更新执行环境值(如果存在的话),否则在shell内部变量中对其进行更改。
约翰

Answers:


26

它们在功能上是等效的。

主要区别在于env FOO=bar baz涉及在shell和之间调用中间过程baz,就像FOO=bar baz直接调用shell一样baz
所以在这方面,FOO=bar baz是首选。

我发现自己使用的唯一情况env FOO=bar是必须将一个命令传递给另一个命令。
作为一个特定的示例,可以说我有一个包装脚本,该脚本对环境进行了一些修改,然后调用exec传递给它的命令,例如:

#!/bin/bash
FOO=bob
some stuff
exec "$@"

如果您将其执行为myscript FOO=bar bazexec将抛出错误,因为exec FOO=bar baz无效。
取而代之的是,您将其称为myscript env FOO=bar baz,将被执行为exec env FOO=bar baz,并且完全有效。


1
您可以这样做FOO=bar exec baz,所以您不需要env最后一点。
斯特凡Chazelas

当您exec做某事时,它会使用您当前的环境吗?
格伦·杰克曼(

1
同上@StephaneChazelas,您也sudo FOO=bar baz可以传递环境变量而无需env
Mike Miller

1
@StephaneChazelas仅在我要添加FOO=bar脚本时才有效。如果FOO并非总是如此bar,我不想对其进行硬编码,而直接将其传递
Patrick

@glennjackman是的,只要在之前导出或传递了变量即可exec,例如FOO=bar exec baz
帕特里克

14

在此特定示例中,假设您的外壳是POSIX兼容外壳,并且假定baz是可执行文件而不是内置的外壳,则没有有效的区别。

如果您的外壳不是 POSIX兼容的外壳,例如cshtcsh,则语法

FOO=bar baz

不起作用,并且没有等效的Shell语法。对于这些外壳,该env命令是覆盖或注入单个命令的环境变量的唯一方法。

例如,如果baz是内置的shell fc,则env不会给出相同的结果,因为它env正在执行一个新进程,而不是直接由命令shell运行。此外,也没有fc可执行的,它只能作为一个shell内建因为它的方式与shell环境交互运行,因此env永远不会与像一个内置的工作fc

另外,env提供了-i选项,该选项使您可以在仅具有一组指定的环境变量的空环境中启动命令。因此env,对于在经过消毒的环境中启动流程非常有用,例如

env -i HOME=/tmp/homedir "PATH=`getconf PATH`" "TERM=$TERM" FOO=bar baz

当我以前使用时,tcsh我会写(setenv FOO bar; baz)得到等效功能。
巴尔2014年

6

除了已经说过的话

VAR=value cmd args > redirs

作为Shell(Bourne / POSIX)功能,您只能限制传递给的环境变量的名称cmd。它们必须是有效的Shell变量名称,并且不得为只读或Shell的特殊变量。

例如,您不能执行以下操作:

1=foo cmd

要么

+++=bar cmd

bash 不允许您执行以下操作:

SHELLOPTS=xtrace cmd

虽然可以做到:

env 1=foo cmd
env +++=bar cmd
env '=baz' cmd

(不是您想要或应该这样做)。要么:

env SHELLOPTS=xtrace cmd

(我有时需要这样做)。

请注意,env您仍然无法传递不包含的环境变量字符串=(这也不是您想要的)。


2

一种用途env是允许$PATH在shebang行中搜索可执行文件(因为在搜索可执行文件时会env考虑$PATH)。如果要调用的可执行文件可能位于不同计算机上的不同位置,则此功能很有用。例如,

#!/usr/bin/env perl

只要目录位于路径中,无论是将其安装在内部/usr/bin/perl还是/usr/local/bin/perl完全不同的位置,安装了可执行位的脚本的第一行中的“行”都将使用Perl执行此脚本。

当然,路径搜索会带来额外的风险,但是,这种风险并不比您显式编写的风险大perl yourscript.pl,后者还会在搜索路径中查找perl。


2

另一个env真正有用的时间是是否要完全控制环境。我运行一个服务器程序(Informix,以防您无法猜测),我想完全控制其环境。我env在脚本的末尾运行它,该脚本将一堆变量设置为正确的值:

env -i HOME="$IXD" \
       INFORMIXDIR="$IXD" \
       INFORMIXSERVER="$IXS" \
       ${IXC:+INFORMIXCONCSMCFG="$IXC"} \
       ${IXH:+INFORMIXSQLHOSTS="$IXH"} \
       IFX_LISTEN_TIMEOUT=3 \
       ONCONFIG="onconfig.$IXS" \
       PATH="/bin:/usr/bin:$IXD/bin" \
       SHELL=/bin/ksh \
       TZ=UTC0 \
    $ONINIT "$@"

-i选项将改变现有环境。后续VAR=value选项设置了我要设置的环境变量;该程序的名称位于中$ONINIT,并且任何命令行参数均通过逐字传递"$@"

所述${IXH:+INFORMIXSQLHOSTS="$IXH"}构建体只传递INFORMIXSQLHOSTS="$IXH"env如果$IXH被设置为一个非空值。

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.