如何在命令行上设置环境变量并使其出现在命令中?

如何在命令行上设置环境变量并使其出现在命令中?

如果我跑

export TEST=foo
echo $TEST

它输出 foo.

如果我跑

TEST=foo echo $TEST

不是。如何在不使用导出或脚本的情况下获得此功能?

答案1

这是因为 shell 扩展了命令行中的变量它实际上运行了该命令,但此时该变量不存在。如果你使用

TEST=foo; echo $TEST

它会起作用的。

export将使该变量出现在随后执行的命令的环境中(有关 bash 中如何工作的信息,请参阅help export)。如果您只需要该变量出现在一个命令的环境中,请使用您尝试过的方法,即:

TEST=foo your-application

shell 语法将其描述为功能上相当于:

export TEST=foo
your-application
unset TEST

规格了解详情。

有趣的是,该export命令切换变量的导出标志姓名。因此,如果你这样做:

unset TEST
export TEST
TEST="foo"

TEST即使在导出时尚未定义,也会被导出。然而,进一步unset应该从中删除导出属性。

答案2

我怀疑你想拥有变量的范围有限,而不是环境变量。环境变量是传递给命令的字符串列表。被处决

var=value echo whatever

您将var=value字符串传递到 echo 接收的环境。但是,echo不会对其环境列表进行任何操作,无论如何,在大多数 shell 中,echo它是内置的,因此不会被处决

如果你写过

var=value sh -c 'echo "$var"'

那就是另一回事了。在这里,我们传递var=valuesh命令,并且sh碰巧使用了它的环境。 shell 将从环境接收到的每个变量转换为 shell 变量,因此接收到的var环境变量sh将被转换为$var变量,并且当它在该命令行中扩展它时echo,它将变成echo value.因为环境默认是继承的,所以echo也会var=value在其环境中接收(或者如果执行的话也会),但同样,echo不关心环境。

现在,如果正如我怀疑的那样,您想要限制 shell 变量的范围,那么有几种可能的方法。

可移植(Bourne 和 POSIX):

(var=value; echo "1: $var"); echo "2: $var"

上面的 (...) 启动一个子 shell(大多数 shell 中的新 shell 进程),因此在那里声明的任何变量只会影响该子 shell,所以我希望上面的代码输出“1: value”和“2:”或“2:之前设置的任何变量”。

对于大多数类似 Bourne 的 shell(参见支持“local”关键字定义局部变量的 shell 列表),您可以使用函数和“本地”内置函数:

f() {
  local var
  var=value
  echo "1: $var"
}
f
echo "2: $var"

通过 zsh,您可以使用匿名函数与普通函数一样,它可以具有局部作用域:

(){ local var=value; echo "1: $var"; }; echo "2: $var"

或者:

function { local var=value; echo "1: $var"; }; echo "2: $var"

对于 bash 和 zsh(但不是 ash、pdksh 或 AT&T ksh),这个技巧也有效:

var=value eval 'echo "1: $var"'; echo "2: $var"

一个可以在更多 shell ( dash, mksh, yash) 中工作的变体,但不能zsh(除非在sh/ksh仿真中):

var=value command eval 'echo "1: $var"'; echo "2: $var"

(在 POSIX shell 中的command特殊内置函数(此处)前面使用eval会消除它们的特殊性(此处,它们前面的变量赋值在返回后仍然有效))

使用fishshell,您可以将变量设置为begin..end块的本地变量:

begin
  set -l var value
  echo 1: $var
end
echo 2: $var

使用mksh(以及很快的 zsh),您可以滥用该${|cmd}构造,该构造也可以具有本地范围,通过确保您不在$REPLY以下范围内设置来确保它扩展为空:

${|local var=value; echo "$var"}; echo "$var"

严格来说,这并不完全正确。一些实现会关心本地化环境变量(LANG, LOCPATH, LC_*...),GNU 实现关心POSIXLY_CORRECT环境变量(env echo --versionenv POSIXLY_CORRECT=1 echo --versionGNU 系统上相比)。

答案3

你做得正确,但 bash 语法很容易被误解:你可能认为这echo $TEST会导致echo获取TESTenv var 然后打印它,但事实并非如此。所以给出

export TEST=123

然后

TEST=456 echo $TEST

涉及以下顺序:

  1. shell解析整个命令行并执行所有变量替换,因此命令行变成

    TEST=456 echo 123
    
  2. 它在命令之前创建临时变量集,因此它保存当前值TEST并用 456 覆盖它;命令行现在是

    echo 123
    
  3. 它执行剩余的命令,在本例中将 123 打印到标准输出(因此剩余的 shell 命令甚至没有使用 的临时值TEST

  4. 它恢复了价值TEST

使用 printenv 代替,因为它不涉及变量替换:

>> export TEST=123
>> printenv TEST
123
>> TEST=456 printenv TEST
456
>> printenv TEST && TEST=456 printenv TEST && TEST=789 printenv TEST && printenv TEST
123
456
789
123
>>

答案4

正如您已经发现的,在 Bash 中,TEST=456 echo $TEST它并不像您预期​​的那样工作,因为您正在访问 shell 当前正在解释的同一行上的变量。但请放心,该变量已在当前命令的持续时间内设置。要验证这一点,您可以执行以下操作:

show () { echo "${!1}" ;}
TEST=456 show TEST

相关内容