如果我跑
export TEST=foo
echo $TEST
它输出 foo.
如果我跑
TEST=foo echo $TEST
不是。如何在不使用导出或脚本的情况下获得此功能?
答案1
这是因为 shell 扩展了命令行中的变量前它实际上运行了该命令,但此时该变量不存在。如果你使用
TEST=foo; echo $TEST
它会起作用的。
export
将使该变量出现在随后执行的命令的环境中(有关 bash 中如何工作的信息,请参阅help export
)。如果您只需要该变量出现在一个命令的环境中,请使用您尝试过的方法,即:
TEST=foo your-application
shell 语法将其描述为功能上相当于:
export TEST=foo
your-application
unset TEST
看规格了解详情。
有趣的是,该export
命令切换变量的导出标志姓名。因此,如果你这样做:
unset TEST
export TEST
TEST="foo"
TEST
即使在导出时尚未定义,也会被导出。然而,进一步unset
应该从中删除导出属性。
答案2
我怀疑你想拥有壳变量的范围有限,而不是环境变量。环境变量是传递给命令的字符串列表。被处决。
在
var=value echo whatever
您将var=value
字符串传递到 echo 接收的环境。但是,echo
不会对其环境列表进行任何操作,无论如何,在大多数 shell 中,echo
它是内置的,因此不会被处决。
如果你写过
var=value sh -c 'echo "$var"'
那就是另一回事了。在这里,我们传递var=value
给sh
命令,并且sh
碰巧使用了它的环境。 shell 将从环境接收到的每个变量转换为 shell 变量,因此接收到的var
环境变量sh
将被转换为$var
变量,并且当它在该命令行中扩展它时echo
,它将变成echo value
.因为环境默认是继承的,所以echo
也会var=value
在其环境中接收(或者如果执行的话也会),但同样,echo
不关心环境。
现在,如果正如我怀疑的那样,您想要限制 shell 变量的范围,那么有几种可能的方法。
可移植(Bourne 和 POSIX):
(var=value; echo "1: $var"); echo "2: $var"
上面的 (...) 启动一个子 shell(大多数 shell 中的新 shell 进程),因此在那里声明的任何变量只会影响该子 shell,所以我希望上面的代码输出“1: value”和“2:”或“2:之前设置的任何变量”。
对于大多数类似 Bourne 的 shell(参见支持“local”关键字定义局部变量的 shell 列表),您可以使用函数和“本地”内置函数:
f() {
local var
var=value
echo "1: $var"
}
f
echo "2: $var"
通过 zsh,您可以使用匿名函数与普通函数一样,它可以具有局部作用域:
(){ local var=value; echo "1: $var"; }; echo "2: $var"
或者:
function { local var=value; echo "1: $var"; }; echo "2: $var"
对于 bash 和 zsh(但不是 ash、pdksh 或 AT&T ksh),这个技巧也有效:
var=value eval 'echo "1: $var"'; echo "2: $var"
一个可以在更多 shell ( dash
, mksh
, yash
) 中工作的变体,但不能zsh
(除非在sh
/ksh
仿真中):
var=value command eval 'echo "1: $var"'; echo "2: $var"
(在 POSIX shell 中的command
特殊内置函数(此处)前面使用eval
会消除它们的特殊性(此处,它们前面的变量赋值在返回后仍然有效))
使用fish
shell,您可以将变量设置为begin
..end
块的本地变量:
begin
set -l var value
echo 1: $var
end
echo 2: $var
使用mksh
(以及很快的 zsh),您可以滥用该${|cmd}
构造,该构造也可以具有本地范围,通过确保您不在$REPLY
以下范围内设置来确保它扩展为空:
${|local var=value; echo "$var"}; echo "$var"
严格来说,这并不完全正确。一些实现会关心本地化环境变量(LANG
, LOCPATH
, LC_*
...),GNU 实现关心POSIXLY_CORRECT
环境变量(env echo --version
与env POSIXLY_CORRECT=1 echo --version
GNU 系统上相比)。
答案3
你做得正确,但 bash 语法很容易被误解:你可能认为这echo $TEST
会导致echo
获取TEST
env var 然后打印它,但事实并非如此。所以给出
export TEST=123
然后
TEST=456 echo $TEST
涉及以下顺序:
shell解析整个命令行并执行所有变量替换,因此命令行变成
TEST=456 echo 123
它在命令之前创建临时变量集,因此它保存当前值
TEST
并用 456 覆盖它;命令行现在是echo 123
它执行剩余的命令,在本例中将 123 打印到标准输出(因此剩余的 shell 命令甚至没有使用 的临时值
TEST
)它恢复了价值
TEST
使用 printenv 代替,因为它不涉及变量替换:
>> export TEST=123
>> printenv TEST
123
>> TEST=456 printenv TEST
456
>> printenv TEST && TEST=456 printenv TEST && TEST=789 printenv TEST && printenv TEST
123
456
789
123
>>
答案4
正如您已经发现的,在 Bash 中,TEST=456 echo $TEST
它并不像您预期的那样工作,因为您正在访问 shell 当前正在解释的同一行上的变量。但请放心,该变量已在当前命令的持续时间内设置。要验证这一点,您可以执行以下操作:
show () { echo "${!1}" ;}
TEST=456 show TEST