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,但同样的问题仍然适用

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


当前回答

如果您想让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

其他回答

export $(grep -v '^#' envfilename | xargs -L 1  -d '\r' -d '\r\n')

这在CentOS上就像一个魅力;当你遇到\r被附加到加载变量的问题时。它还负责注释和空白。

我在Mac上使用docker-compose和.env文件,并想将.env导入到我的bash shell中(用于测试),这里的“最佳”答案是在以下变量上出错:

.env

NODE_ARGS=--expose-gc --max_old_space_size=2048

解决方案

所以我最终使用eval,并将env var defs包装在单引号中。

eval $(grep -v -e '^#' .env | xargs -I {} echo export \'{}\')

Bash的版本

$ /bin/bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
Copyright (C) 2007 Free Software Foundation, Inc.

问题与您的方法是导出在while循环发生在一个子shell,这些变量将不可用在当前shell(父shell的while循环)。

在文件本身中添加export命令:

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

然后你需要在当前shell中的文件中使用:

. ./conf/prac1

OR

source ./conf/prac1

这可能会有帮助:

export $(cat .env | xargs) && rails c

我使用这个的原因是如果我想在我的rails控制台中测试。env的东西。

Gabrielf想出了一个保持变量局部的好方法。这解决了从一个项目到另一个项目时的潜在问题。

env $(cat .env | xargs) rails

我已经用bash 3.2.51(1)-release测试了这一点


更新:

要忽略以#开头的行,使用这个(感谢Pete的评论):

export $(grep -v '^#' .env | xargs)

如果你想取消文件中定义的所有变量,使用这个:

unset $(grep -v '^#' .env | sed -E 's/(.*)=.*/\1/' | xargs)

更新:

要处理带有空格的值,请使用:

export $(grep -v '^#' .env | xargs -d '\n')

在GNU系统上——或者:

export $(grep -v '^#' .env | xargs -0)

在BSD系统上。


从这个答案中,你可以自动检测操作系统:

export-env.sh

#!/bin/sh

## Usage:
##   . ./export-env.sh ; $COMMAND
##   . ./export-env.sh ; echo ${MINIENTREGA_FECHALIMITE}

unamestr=$(uname)
if [ "$unamestr" = 'Linux' ]; then

  export $(grep -v '^#' .env | xargs -d '\n')

elif [ "$unamestr" = 'FreeBSD' ] || [ "$unamestr" = 'Darwin' ]; then

  export $(grep -v '^#' .env | xargs -0)

fi

我对此的贡献是对@的答案的扩展 User4040650允许在git repo中轻松使用。它将尝试从当前目录中获取。env文件,如果不存在,则从你所在的git repo中获取。env文件。如果你已经cd到子目录中,那么就不需要源../../,这是很有帮助的。环境之类的。

我把它放在我的.bashrc中,所以我只需要在需要的地方调用setenv

setenv() {
  local env_path
  if { [ -f .env ] && env_path='.env'; } || { env_path=$(git  rev-parse --show-toplevel 2>/dev/null)/.env && [ -f "$env_path" ]; }; then
    echo "sourcing $env_path"
    set -o allexport
    source "$env_path"
    set +o allexport
  else
    echo "No env file found"
  fi
}