Answers:
这取决于评估命令的不同步骤的顺序。
A=10 echo $A
首先将命令解析为由三个单词组成的简单命令A=10
,echo
然后$A
。然后,每个单词都经过变量替换,$A
即将变量扩展转换为值(例如,省略了看不见的步骤)。
如果A
具有值foo
最初,扩张步骤的结果是仍具有三个词一个简单的命令:A=10
,echo
和foo
。(外壳程序此时还记住哪些字符最初在引号中,在这种情况下,没有字符。)下一步是执行命令。由于A=10
以有效的变量名开头,后跟等号,因此将其视为赋值。在执行命令期间,该变量在外壳程序和环境中均A
设置为10
。(通常,您需要编写在环境中export A
具有A
的属性,而不仅仅是将其作为shell变量;这是一个例外。)下一个单词不是赋值,因此将其视为命令名(这是内置命令)。的echo
命令不依赖于任何变量,因此A=10 echo $A
具有与完全相同的效果echo $A
。
如果仅在命令执行期间设置变量,但在执行命令时将分配考虑在内,则可以使用子外壳。用括号指示的子shell使所有状态更改(变量分配,当前目录,函数定义等)在该子shell本地。
(A=10; echo $A)
作出这样的export A=10
,如果你想将变量导出到环境,以便它是由外部程序可见。
A=10; (echo $A)
输出,10
但也A
为脚本的其余部分设置。
A=10 eval 'echo $A'
。单引号将停止$A
解释,直到对整行进行评估为止。此时A = 10。我认为这个答案比公认的更正确。
$A
和的分配的顺序A
。例如,不A=5; A=6 let 'a=A'; echo $a
返回,并且我不认为启动子shell是因为它是内置命令。6
5
let
A=10 echo $A
将不设置A=10
任何命令之后,即使它们是在不同的线(时明确分配了已经评价)。这与顺序无关,与范围
当您使用LANG=C gcc ...
时,shell 只会为gcc
的环境设置LANG ,而不会为当前环境本身设置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
最后但并非最不重要的一点是,有必要了解shell和环境变量以及程序参数之间的区别。
这里有一些很好的参考:
。
(*)注:技术上的外壳并在当前的环境设置过,这里的原因:有些命令,比如echo
,read
和test
是shell内建的,因此它们不会产生一个子进程。它们在当前环境中运行。但是shell会注意分配只持续到命令运行为止,因此对于所有实际目的,效果是相同的:分配只能由该单个命令看到。
$A
在分配发生之前进行评估。我认为您的解释只会在常规内置实用程序的情况下失败,这些实用程序的行为取决于变量的值:内置程序确实会看到分配的值。一个常见的示例是IFS=: read one two three rest
,它读取以冒号分隔的字段:read
内建函数确实看到的值IFS
。
echo
将看到价值10
的A
,如果它的照顾。
pid
)不会像其他“常规”命令那样看到分配。但是在完成命令以限制分配范围后,它会取消设置。这是正确的吗,我将相应地解决我的答案。PS:除了技术方面,我仍然认为答案应该侧重于范围方面,而不是评估顺序,否则人们会认为A=10 test; echo $A
将打印10
A=10 (echo $A)
得到10
吗?