当前位置: 首页>>技术教程>>正文


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

, ,

问题描述

该命令:

A=10 echo $A

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

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

我用了

LANG=C gcc ...

强制gcc使用后备语言(英语)而不是系统语言(中文)。因此,我假设VAR=value前缀将为其后的命令设置一个临时环境。但是看起来我有点误会。

最佳答案

这取决于评估命令的不同步骤的顺序。

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

如果A最初的值为foo,则扩展步骤的结果是一个简单的命令,该命令仍包含三个单词:A=10echofoo。 ( shell 程序此时还记得哪些字符最初在引号中-在这种情况下,没有字符。)下一步是执行命令。由于A=10以有效的变量名开头,后跟等号,因此将其视为赋值。在执行命令期间,在 shell 程序和环境中,变量A均设置为10。 (通常,您需要编写export A才能在环境中包含A,而不仅仅是将其作为shell变量;这是一个例外。)下一个字不是赋值,因此将其视为命令名(这是内置命令)。 echo命令不依赖任何变量,因此A=10 echo $A具有与echo $A完全相同的效果。

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

(A=10; echo $A)

如果要将变量导出到环境中,以便外部程序可以看到它,则使该export A=10

次佳答案

当您使用LANG=C gcc ...时,会发生的情况是 shell 程序仅针对gcc的环境设置了LANG,而不为当前环境本身设置了LANG(请参见注释)。因此,在gcc完成后,LANG返回其先前的值(或未设置)。

此外,当您使用A=10 echo $A时,它是用 shell 程序代替$ A而不是echo,并且此替换(称为”expansion”)在评估语句(包括赋值)之前发生,因此必须按预期的方式工作A的值在当前环境中声明之前。

这就是为什么A=10 echo $A无法按预期工作的原因:将为echo设置A=10,但是echo内部忽略了环境变量A的值。然后,将$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"

将其另存为testscript并尝试:

$ A=5; A=10 testscript "$A"; echo "$A"
1st argument is 5
A is 10
5

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

这里有一些很好的参考:

(*)注意:从技术上讲,shell确实也可以在当前环境中设置,这是为什么:一些命令(例如echoreadtest)是shell内置的,因此它们不会产生子进程。它们在当前环境中运行。但是shell会注意分配只持续到命令运行为止,因此对于所有实际目的,效果是相同的:分配只能由该单个命令看到。

第三种答案

执行您显然想要的一种可能的干净方法是发出命令:

A=10 eval 'echo $A'

实际上,这会将值10的替换推迟到$ A的后面的上下文中(即,’inside’ eval,它已经知道分配)。请注意,单引号必不可少。这样的构造干净利落地将分配传达给您所需的命令(在这种情况下为回声),而不会冒污染当前环境的风险。

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/9580.html,未经允许,请勿转载。