在命令行中动态建立环境变量

时间:2019-12-23 14:39:26

标签: bash parsing

我有以下脚本:

#!/bin/bash

echo $FAV_FRUIT
echo $FAV_HERO

以及以下txt文件:

FAV_FRUIT='watermelon'
FAV_HERO='batman'

我试图了解为什么这不起作用:

$(cat environment.txt | tr '\n' ' ' ) ./printEnv.sh 
bash: FAV_FRUIT='watermelon' FAV_HERO='batman' : command not found

但是如果我真的这样做:

FAV_FRUIT='watermelon' FAV_HERO='batman' ./printEnv.sh 

然后我得到正确的输出。

如何修复我的命令以使其成功?

3 个答案:

答案 0 :(得分:1)

我不认为错误消息来自您声称已执行的行:

$ $(cat environment.txt | tr '\n' ' ' ) ./printEnv.sh 
FAV_FRUIT='watermelon': command not found

这是我想你写的。看到区别了吗?

$ "$(cat environment.txt | tr '\n' ' ' )" ./printEnv.sh 
FAV_FRUIT='watermelon' FAV_HERO='batman' : command not found

无论如何,$(...)替换被视为命令(或在第一种情况下为命令和自变量)而不是临时变量分配的原因很简单。语法var=value prog args就是:语法。 Bash会先进行命令行解析,然后再执行替换操作,并且在解析期间它会识别单词是临时环境分配。

在解析命令之后,它将找出哪些词是临时分配的,哪些词是重定向的,并将其分开。然后,它执行各种替换,然后复制其余的单词(引号之外的单词),并使用第一个作为执行命令。 (参数分配和重定向也进行替换,但不进行单词拆分。之后它们仍然是分配和重定向。)

这意味着作业键入时必须看起来像作业。变量名称必须是有效的变量名称,因此它不能包含任何替换。只有值部分会进行替换。

完成您似乎要尝试执行的操作的最简单方法是使用标准命令行实用程序env。例如,您可以这样写:

env $(cat environment.txt | tr '\n' ' ' ) ./printEnv.sh

但是要当心! bash进行替换时,不会删除文本文件中的单引号。因此结果将是:

'watermelon'
'batman'

而不是

watermelon
batman

要获得正确的输出,只需将单引号放在文件之外。请注意,tr命令是不必要的,因为分词也适用于换行符。

到目前为止,一切都很好。但这仅在文件environment.txt中的行中不包含空格或制表符或任何其他可能扩展的字符(例如*)时有效。那不是很令人满意。而且,您不能仅引用$(...),因为它将是一个单独的参数,env将被视为单个环境赋值(就像它被视为代表命令名称的单个单词一样)。原始尝试)。

此问题的通常解决方案是使用bash数组。 (再次,我从environment.txt中删除了单引号,以便可以正常使用。)

$ mapfile  assignments < environment.txt 
$ env "${assignments[@]}" ./printEnv.sh
watermelon
batman

答案 1 :(得分:1)

如果不希望将$()的结果解释为命令,则可以使用env

    env $(cat environment.txt | tr '\n' ' ' ) ./printEnv.sh

export不同,env仅临时设置变量。如果之后执行echo $FAV_FRUIT,将得到一个空的输出。

请参见https://ss64.com/bash/env.html

答案 2 :(得分:0)

在文件printEnv.sh中,您可以将以下行作为第一行添加(在shebang之后):

source environment.txt