(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"
key=${kv%%=*}
优于key=${kv%=*}
因为%%和##与%和#不同,因为删除部分是否是最短或最长的可移动部件