在 bash(或其他)中设置变量环境变量

在 bash(或其他)中设置变量环境变量

我希望我的脚本读取包含要设置的环境变量的键/值对的文件,然后设置它们。

到目前为止,我有这个:

#!/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

相关内容