为什么“A=10 echo $A”不打印 10?

Ear*_*ine 25 command-line bash environment-variables

这个命令:

A=10 echo $A
Run Code Online (Sandbox Code Playgroud)

打印一个空行。为什么不10呢?为什么就地临时环境设置不起作用?

我想知道原因和解释而不是解决方案。

我用了

LANG=C gcc ...
Run Code Online (Sandbox Code Playgroud)

强制 gcc 使用回退语言(英语)而不是系统语言(中文)。所以我假设VAR=value前缀将为它后面的命令设置一个临时环境。不过我好像有点误会了。

Mes*_*ion 37

当您使用LANG=C gcc ... 时,shell仅为gcc的环境设置 LANG ,而不是当前环境本身设置 LANG (请参阅注释)。因此,完成后,将恢复到其先前的值(或未设置)。gccLANG

此外,当您使用A=10 echo $A它时,替换 $A 的是shell,而不是 echo,并且这种替换(称为“扩展”)发生评估语句(包括赋值)之前,因此要按预期工作,A必须已经设置了在该声明之前的当前环境中。

这就是为什么A=10 echo $A不能按预期工作的原因:A=10将为 echo 设置,但 echo 在内部忽略环境变量的值A。And$A替换为当前 shell 中设置的值(无),然后作为参数传递给 echo。

所以你的假设是正确的:VAR=value command 确实有效,但这仅在command内部使用VAR时才相关。如果没有,您仍然可以将其value作为参数传递给command,但参数会被当前的shell替换,因此必须在使用之前设置它们:VAR=value; command "$VAR"

如果你知道如何创建一个可执行脚本,你可以试试这个作为测试:

#!/bin/sh
echo "1st argument is $1"
echo "A is $A"
Run Code Online (Sandbox Code Playgroud)

将其另存为testscript并尝试:

$ A=5; A=10 testscript "$A"; echo "$A"
1st argument is 5
A is 10
5
Run Code Online (Sandbox Code Playgroud)

最后但并非最不重要的一点是,有必要了解shell环境变量以及程序参数之间的区别。

这里有一些很好的参考:

.

(*) 注意:从技术上讲,shell也会在当前环境设置,原因如下:某些命令,例如echo,readtestshell 内置命令,因此它们不会产生子进程。它们在当前环境中运行。但是 shell 负责分配只持续到命令运行,所以对于所有实际目的来说效果是一样的:分配只能由单个命令看到。

  • 这种解释实际上是不正确的,尽管它在除少数极端情况之外的所有情况下都能得出正确的结论。真正的解释是扩展顺序:在赋值之前评估`$A`。我认为您的解释仅在常规内置实用程序的情况下失败,其行为取决于变量的值:内置程序确实看到了分配的值。一个常见的例子是 `IFS=: read one two Three rest`,它读取冒号分隔的字段:`read` 内置函数确实看到了 `IFS` 的值。 (2认同)

Gil*_*il' 22

这是评估命令的不同步骤发生的顺序的问题。

A=10 echo $A首先将命令解析为由三个单词组成的简单命令A=10echo$A。然后每个单词都经过变量替换,$A即将变量扩展如转换为它们的值(我省略了不做任何可见的步骤)。

如果最初A具有值foo,则扩展步骤的结果是一个简单的命令,它仍然包含三个字:A=10,echofoo。(此时,shell 还会记住哪些字符最初在引号内——在本例中,没有。)下一步是执行命令。由于A=10以有效的变量名开头,后跟等号,因此被视为赋值;在命令执行期间,该变量在 shell 和环境中都A设置为10。(通常您需要在环境中写入export AhaveA而不仅仅是作为 shell 变量;这是一个例外。)下一个单词不是赋值,因此它被视为命令名称(它是一个内置命令)。这echocommand 不依赖于任何变量,因此A=10 echo $Aecho $A.

如果只想在命令的持续时间内设置变量,但在执行命令时考虑赋值,则可以使用子shell。由括号指示的子shell 使所有状态更改(变量分配、当前目录、函数定义等)成为子shell 本地的。

(A=10; echo $A)
Run Code Online (Sandbox Code Playgroud)

作出这样的export A=10,如果你想将变量导出到环境,以便它是由外部程序可见。

  • @EarthEngine 不,那将是语法错误。分配必须在一个简单命令的开头(即只是一个命令名称和一些参数,以及可选的一些初始分配和一些重定向)。`A=10; (echo $A)` 输出 `10`,但也会为脚本的其余部分设置 `A`。 (2认同)
  • @EarthEngine 但是你可以说`A=10 eval 'echo $A'`。单引号停止解释`$A`,直到整行被评估......到那时A = 10。我认为这个答案*比公认的更正确*。 (2认同)