bash脚本在命令中的临时值


11

像下面的命令一样,

if true; then
   IFS=":" read a b c d e f <<< "$test"

书中说,IFS ":"在主命令(read a b c d e f <<< "$value")之前使用值分配命令()时,其值暂时对主命令有效。因此,该read命令使用delimiter :

但是,就像这个命令

if true; then
   HOME="hello" echo "$HOME"

回声不是你好。以上命令的真正含义是什么?

Answers:


5

这归结为评估工作原理的问题。这两个示例都以相同的方式工作,出现问题的原因在于shell(此处为bash)如何扩展变量。

编写此命令时:

HOME="foo" echo $HOME

$HOME扩展在运行命令之前。因此,它被扩展为原始值,而不是您为命令设置的新值。HOMEecho运行命令的环境中确实已更改了该变量,但是,您正在$HOME从父级打印。

为了说明这一点,考虑一下:

$ HOME="foo" bash -c 'echo $HOME'
foo
$ echo $HOME
/home/terdon

如您在上方所见,第一个命令打印了临时更改的值,HOME第二个命令打印了原始值,表明该变量只是临时更改了。由于bash -c ...命令用单引号(' ')而不是双引号()引起来" ",因此该变量不会扩展,而是按原样传递给新的bash进程。然后,此新过程将其展开并打印已设置为的新值。如果使用,您会看到这种情况set -x

$ set -x
$ HOME="hello" echo "$HOME"
+ HOME=hello         
+ echo hello
hello

如您在上方所见,变量 $HOME从未传递给echo。它只会看到其扩展的价值。与之比较:

$ HOME="hello" bash -c 'echo $HOME'
+ HOME=hello
+ bash -c 'echo $HOME'
hello

在这里,由于使用单引号,因此将变量而不是其值传递给新进程。


7

当shell解析一行时,它将把该行标记为单词,对单词执行各种扩展(按顺序),然​​后执行命令。

假设 test=1:2:3:4:5:6

让我们看一下以下命令: IFS=":" read a b c d e f <<< "$test"

分词后,将发生参数扩展IFS=":" read a b c d e f <<< "1:2:3:4:5:6"

Shell将在读取命令期间设置IFS变量,并read知道如何将$ IFS应用于其输入,并为变量名称提供值。

此命令的故事类似,但结果不同: HOME="hello" echo "$HOME"

由于参数扩展发生命令开始之前,因此shell具有:

HOME="hello" echo "/home/username"

然后,在执行echo命令期间,根本不使用$ HOME的新值。

要实现您要执行的操作,请选择以下一项

# Delay expansion of the variable until its new value is set
HOME="hello" eval 'echo "$HOME"'

要么

# Using a subshell, so the altered env variable does not affect the parent.
# The semicolon means that the variable assignment will occur before
# the variable expansion
(HOME="hello"; echo "$HOME")

但不要选择第一个。


最好选择第一个。至少它明显更快。当eval是答案时,您有时可能会问错问题。但是,如果有人出于某些原因必须这样做,那么更改答案并不会使问题本身的错误程度有所降低。另一个解决方案是将其包装在函数中并使用local
user23013

为什么要eval避免该解决方案?
DarkHeart '16

如果您不严格控制输入,则必须非常小心允许其他人注入到程序中的代码。
格伦·杰克曼

-1

有两个作用域:环境变量和局部变量。环境变量的有效期为每一个过程(见setenvgetenv),而局部变量只能在这个shell会话是活动的。(这不是明显的区别...)

暗示的env(如您的示例所示)修改环境,而echo ...使用本地环境-因此env无效。

例如,要修改局部变量,请使用

( HOME="foo" ; echo "$HOME" )

在此,括号定义了此分配的范围。


1
这与变量作用域无关,问题是在将变量传递给子外壳程序之前先对其进行扩展。
terdon
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.