TL;DR:如何从文本文件中导出一组键/值对到shell环境中?


为了记录在案,以下是问题的原始版本,并附有示例。

我在bash中写了一个脚本,它在某个文件夹中解析带有3个变量的文件,这是其中之一:

MINIENTREGA_FECHALIMITE="2011-03-31"
MINIENTREGA_FICHEROS="informe.txt programa.c"
MINIENTREGA_DESTINO="./destino/entrega-prac1"

该文件的存放路径为。/conf/prac1

我的脚本minientrega.sh然后使用以下代码解析文件:

cat ./conf/$1 | while read line; do
    export $line
done

但是当我在命令行中执行minientrega.sh prac1时,它不会设置环境变量

我也尝试使用source ./conf/$1,但同样的问题仍然适用

也许还有其他方法可以做到这一点,我只需要使用我传递的文件的环境变量作为脚本的参数。


当前回答

使用shdotenv

dotenv支持shell和posix兼容的.env语法规范 https://github.com/ko1nksm/shdotenv

eval "$(shdotenv)"

使用

Usage: shdotenv [OPTION]... [--] [COMMAND [ARG]...]

  -d, --dialect DIALECT  Specify the .env dialect [default: posix]
                           (posix, ruby, node, python, php, go, rust, docker)
  -s, --shell SHELL      Output in the specified shell format [default: posix]
                           (posix, fish)
  -e, --env ENV_PATH     Location of the .env file [default: .env]
                           Multiple -e options are allowed
  -o, --overload         Overload predefined environment variables
  -n, --noexport         Do not export keys without export prefix
  -g, --grep PATTERN     Output only those that match the regexp pattern
  -k, --keyonly          Output only variable names
  -q, --quiet            Suppress all output
  -v, --version          Show the version and exit
  -h, --help             Show this message and exit

需求

Shdotenv是一个内置awk脚本的单文件shell脚本。

POSIX shell (dash, bash, ksh, zsh, etc) awk (gawk, nawk, mawk, busybox awk)

其他回答

source的问题在于它要求文件具有正确的bash语法,而一些特殊字符会破坏它:=、"、'、<、>等。所以在某些情况下你可以

source development.env

它会起作用的。

然而,这个版本可以承受值中的所有特殊字符:

set -a
source <(cat development.env | \
    sed -e '/^#/d;/^\s*$/d' -e "s/'/'\\\''/g" -e "s/=\(.*\)/='\1'/g")
set +a

解释:

-a意味着每个bash变量都将成为环境变量 /^#/d删除注释(以#开头的字符串) /^\s*$/d删除空字符串,包括空格 "s/'/'\\\ " /g"将每个单引号替换为'\ ",这是bash中的一个生成引号的技巧序列:) "s/=\(.*\)/='\1'/g"将每个a=b转换为a='b'

因此,你可以使用特殊字符:)

要调试这段代码,将source替换为cat,您将看到该命令产生的结果。

我的要求是:

简单的.env文件,没有导出前缀(为了与dotenv兼容) 支持值在引号中:TEXT="alpha bravo charlie" 支持以#和空行作为前缀的注释 通用的mac/BSD和linux/GNU

完整的工作版本编译自上述答案:

  set -o allexport
  eval $(grep -v '^#' .env | sed 's/^/export /')
  set +o allexport

如果您想让exec作为脚本的最后一个命令,那么您可以使用execlineb解释器。这是脚本的最后一行:

#!/bin/sh
...
exec envfile -I /etc/default/bla envfile /etc/default/bla-bla my_cmd

envfile……是来自execline套件的命令,它们依赖于“链加载”。 顺便说一句,一旦你进入这个兔子洞,你可能会发现你不再需要壳了(…-)使用execlineb解释器而不是shell来启动服务,以最小的开销是非常有用的,即:

#!/bin/execlineb
...
envfile -I /etc/default/bla
envfile /etc/default/bla-bla
my_cmd

如果你想保持全局环境变量空间不变,我的看法是,我认为这是可取的。

创建一个像这样的脚本:

# !/bin/sh
set -o allexport
source $1
set +o allexport
shift
exec $@

然后像这样使用:

dotenv env-file my-binary

不知道为什么,或者我错过了什么,但在经历了大部分答案和失败之后。我意识到通过这个。env文件:

MY_VAR="hello there!"
MY_OTHER_VAR=123

我可以简单地这样做:

source .env
echo $MY_VAR

输出:你好!

似乎在Ubuntu linux中工作得很好。