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

Bash 在命令行中动态建立环境变量,bash,parsing,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 但如果我真的这么

我有以下脚本:

#!/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 
然后我得到正确的输出


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

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

source environment.txt

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

source environment.txt

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

$ $(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
我不认为错误消息来自您声称执行的那行代码:

$ $(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
如果不想将$()的结果解释为命令,可以使用
env

    env $(cat environment.txt | tr '\n' ' ' ) ./printEnv.sh
与导出不同,
env
仅临时设置变量。如果您在之后执行echo$FAV_FRUIT,您将得到一个空输出


请参见

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