假设我有这个.env
文件:
A=1
B=2
C="3 4 5"
如果我跑set -x; echo $(cat .env | xargs)
:
++ cat .env
++ xargs
+ echo A=1 B=2 C=3 4 5
A=1 B=2 C=3 4 5
如果我跑set -x; export $(cat .env | xargs)
:
++ cat /tmp/test.env
++ xargs
+ export A=1 B=2 C=3 4 5
+ A=1
+ B=2
+ C=3
bash: export: `4': not a valid identifier
bash: export: `5': not a valid identifier
然后我尝试了很多其他技巧来尝试保留或在C
值周围添加引号:
$ set -x; export $(cat /tmp/test.env | xargs printf %q)
+ set -x
++ cat /tmp/test.env
++ xargs printf %q
+ export ''\''A=1'\'''\''B=2'\'''\''C=3' 4 '5'\'''
bash: export: `'A=1''B=2''C=3': not a valid identifier
bash: export: `4': not a valid identifier
bash: export: `5'': not a valid identifier
无论我做什么,C
值总是按空格分割。
编辑:为了澄清,一个基于天真地采购 .env 文件的解决方案(大多数解决方案来自如何从文件中导出变量?)如果文件包含任何可以解释为命令执行的字符串,则非常不安全。我希望我的环境文件仅被解释为键值数据。
答案1
你能用吗parset
?
parset "`perl -nE '/[^=]+/ && print "$&,"' .env`" echo ::: "`perl -pe 's/[^=]+=//' .env`"
它可以愉快地处理如下输入:
vv=* ; & " echo this is a value - not a command
答案2
xargs
确实理解引用(尽管与 POSIX shell 的方式不完全相同),但运行xargs export
不起作用,因为xargs
只能运行独立的可执行文件,而不是 shell 的内置命令,例如export
通常xargs
不是内置命令。
不带引号的$(...)
shell 构造本身执行 IFS 分割 + 通配符(不是 中的后者zsh
),并且不处理引号(并且您不希望此处使用通配符部分)。
然而,由于您的 shell 是bash
,您可以通过调用从文件中读取的记录来xargs
输出 NUL 分隔的记录,并在 bash 中使用(需要 bash 4.4+ for )来拆分它,而不是 split+glob 运算符:printf '%s\0'
readarray -td ''
-d
readarray -td '' assignments < <(xargs -r < .env printf '%s\0')
(( ${#assignments[@]} == 0 )) || export -- "${assignments[@]}"
(这里使用 GNU 风格的-r
选项来避免printf
在输入没有记录时运行)。