此命令:
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
最后但同样重要的是,值得了解的是壳和环境变量和程序参数。
以下是一些很好的参考:
。
(*)注:从技术上讲,外壳做也在当前环境中设置,原因如下:某些命令,如echo
、read
和test
是shell 内置命令,因此它们不会生成子进程。它们在当前环境中运行。但 shell 负责的分配只持续到命令运行为止,因此从实际目的来看,效果是一样的:分配只能由该单个命令看到。
答案2
这是关于评估命令的不同步骤发生的顺序的问题。
A=10 echo $A
首先将命令解析为由三个单词组成的简单命令A=10
,echo
和$A
。然后每个单词经历变量替换,即将变量扩展转换为$A
它们的值(我省略了不执行任何可见操作的步骤)。
如果最初A
具有值foo
,则扩展步骤的结果是一个仍然包含三个单词的简单命令:A=10
、echo
和foo
。 (此时 shell 还会记住最初在引号内的字符 — — 在本例中为无。)下一步是执行该命令。由于A=10
以有效变量名后跟等号开头,因此它被视为赋值;在命令执行期间,该变量在 shell 和环境中都A
设置为10
。 (通常需要在环境中写入export A
have 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),而不会冒污染当前环境的风险。