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


9

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

到目前为止,我有这个:

#!/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"哪里,因此我只需要替换该行即可。


有点偏离主题,但是由于我在尝试模仿您的脚本时被卡住了,所以我在共享...抓取钥匙时...使用key=${kv%%=*}优于key=${kv%=*}因为%%和##与%和#不同,因为删除部分是否是最短或最长的可移动部件
pulkitsinghal 2013年

Answers:


10

export $key=$val应该在中工作得很好bash。我怀疑您的问题是管道(|)。管道中的所有命令都在子Shell中执行。在您的示例中bash,正在运行脚本的实例将派生两个子shell:一个用于cat $1,另一个用于while read ...。在运行while循环的子外壳中分配和导出变量,然后在子外壳退出时立即将所有变量丢弃。解决此问题的一种方法是根本不产生子外壳。代替不必要地使用cat,请尝试重定向:

while read ...; do
   ...
done < "$1"

BashFAQ 24更详细地说明了这一点。

另一种方法是仅导出文件,并导出:

. <(sed '/^export/!s/^/export /' "$1")

<( )是进程替换。

请特别注意,由于您正在从参数读取环境变量,因此必须确保参数文件$1是受信任的源,以便它不会对脚本造成不良影响。


我以前使用过重定向;当我将脚本更改为使用时,其他某些东西一定没有用cat。但是,带有重定向的脚本现在可以工作了,谢谢!
palswim 2012年

无用的猫被认为是有害的!
2014年

2

jw013已经给出了正确的答案,但是我想指出其他一些问题。)

管道的右侧在其自己的bash子外壳中(以及大多数其他外壳中运行,但ATT ksh和zsh除外)。因此,您要在执行循环的子外壳中设置环境变量,而不是在主外壳进程中设置环境变量。

这里有一个简单的解决方法,即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#*=}"; 否则,外壳程序将对其进行单词拆分和文件名生成(即,globbing)。其次,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"


0

/ env

EXPORT=value
#NOTEXPORT=notvalue

脚本

#!/bin/sh

for entry in $(cat /env)
do
  if [[ ! $entry == \#* ]]
  then
    export $entry
  fi
done
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.