我希望我的脚本读取包含要设置的环境变量的键/值对的文件,然后设置它们。
到目前为止,我有这个:
#!/bin/bash
cat $1 | while read kv
do
key=${kv%=*}
val=`echo ${kv#*=} | sed 's/^"\|"$//g'`
export $key="$val"
done
我想读取这样的文件:
XAUTHLOCALHOSTNAME="localhost"
DISPLAY=":0"
XAUTHORITY="/tmp/some-XAuthority"
我只需要在脚本持续时间内使用这些变量,因此我不需要解决以下问题在脚本中为父作用域设置变量。
根据我的测试,我认为我的问题在于export $key="$val"
,所以我想我只需要更换该线。
答案1
export $key=$val
应该工作得很好bash
。我怀疑你的问题是管道(|
)。管道中的所有命令都在子 shell 中执行。在您的示例中,运行脚本的实例bash
将分叉 2 个子 shell:一个用于,cat $1
另一个用于while read ...
.变量在运行 while 循环的子 shell 中进行赋值和导出,然后当子 shell 退出时,所有变量都会立即被抛出。解决此问题的一种方法是根本不生成子 shell。代替对猫的无用利用,尝试重定向:
while read ...; do
...
done < "$1"
Bash常见问题解答 24更详细地解释了这一点。
另一种方法是仅获取文件的源,并添加导出:
. <(sed '/^export/!s/^/export /' "$1")
这<( )
是过程替换。
另外需要注意的是,由于您正在从参数中读取环境变量,因此必须确保参数文件$1
是受信任的源,这样它就不会对您的脚本做坏事。
答案2
(jw013 已经给出了正确答案,但我想指出更多问题。)
管道的右侧在 bash 中自己的子 shell 中运行(以及大多数其他 shell,但 ATT ksh 和 zsh 除外)。因此,您要在执行循环的子 shell 中设置环境变量,而不是在主 shell 进程中设置环境变量。
这里有一个简单的修复方法,就是cat
通过重定向来替换无用的使用:
while read …; do …; done <"$1"
一般来说,如果您需要预处理输入,请将循环和脚本的其余部分(至少是需要更改变量的部分)放在一个块中。
grep '^foo_' "$1" | {
while read …; do …; done
do_something
}
请注意,一般来说,while read line; do …
不会完全迭代输入行。看为什么while IFS= read
如此频繁地使用而不是IFS=; while read..
?以获得解释。迭代输入行的正确习惯用法是
while IFS= read -r line; do …
在这里,删除前导和尾随空格并不重要,因为不应该有任何给定的示例输入,但您可能需要-r
避免反斜杠扩展。这while read line
实际上可能是读取输入的正确方法(但我怀疑只有变量值不包含换行符时)。您的输入格式也可能不明确或解析起来更复杂。检查如果变量值之一包含换行符、双引号或反斜杠会发生什么情况。
您肯定会破坏输入的一点是当您提取值时:
val=`echo ${kv#*=} | sed 's/^"\|"$//g'`
首先,您需要在变量替换周围使用双引号:echo "${kv#*=}"
;否则,shell 将对其执行分词和文件名生成(即通配符)。其次,echo
这不是打印字符串的可靠方法,因为某些以 a 开头的字符串-
被视为选项,并且某些 shell 对参数执行反斜杠扩展。一种可靠且便携的打印字符串的方法是printf %s "${kv#*=}"
.另外,如果值跨越多行,sed 程序将分别对每一行进行操作,这是错误的。这是可以修复的,但有一个更简单的方法,那就是使用 shell 的字符串操作工具:val=${kv#*=}; val=${val#\"}; val=${val%\"}
。
假设您的输入已使用 plain 正确解析read
,则有一种更简单的解析方法,利用IFS
设置来分割每一行:
while read name value; do
value=${value#\"}; value=${value%\"}
export name="$value"
done <"$1"
答案3
另一个不错的选择可能是将其放入export
文件中并获取它:
export XAUTHLOCALHOSTNAME="localhost"
export DISPLAY=":0"
export XAUTHORITY="/tmp/some-XAuthority"
进而:
. "$1"
答案4
使用eval
救援(这对我有用):
key=andre # Set the key
val=3000 # Set the value
eval "export ${key}=${val}";
echo $andre # Prints 3000