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

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

此命令:

A=10 echo $A

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

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

我用了

LANG=C gcc ...

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

答案1

当您使用时,LANG=C gcc ... shell 会为gcc环境设置 LANG仅有的, 和不是为了当前的环境本身(看注释)。因此gcc完成后,LANG将恢复为其先前的值(或取消设置)。

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

这就是为什么A=10 echo $A不能按预期工作的原因:A=10将为 echo 设置,但 echo 内部会忽略环境变量的值A。并$A替换为在当前外壳(无),以及然后作为参数传递给 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

最后但同样重要的是,值得了解的是环境变量和程序参数

以下是一些很好的参考:

(*)注:从技术上讲,外壳也在当前环境中设置,原因如下:某些命令,如echoreadtestshell 内置命令,因此它们不会生成子进程。它们在当前环境中运行。但 shell 负责的分配只持续到命令运行为止,因此从实际目的来看,效果是一样的:分配只能由该单个命令看到。

答案2

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

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

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

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

(A=10; echo $A)

export A=10如果您想将变量导出到环境中以便外部程序可以看到它,请这样做。

答案3

执行您显然想要的操作的一个可能干净的方法是发出以下命令:

A=10 eval 'echo $A'

这实际上将把值 10 替换到 $A 的位置,推迟到后面的上下文(即 eval 的“内部”,它已经知道赋值)。请注意,单引号是必不可少的。这样的构造可以清楚地将赋值传达给您所需的命令(在本例中为 echo),而不会冒污染当前环境的风险。

相关内容