Я пытаюсь загрузить переменные среды из файла file.env в Bash. Трудности возникают, если файл содержит комплексные переменные. Пример файла.env (переменная NODE)
# DB
; TEST
DB_USER=test
DB_HOST=localhost
DB_PORT=5432
DB_NAME=test
NODE='{"node0001": "127.0.0.1","node0002": "127.0.0.2","node0003": "127.0.0.3"}'
# API
API_PORT=8081
API_LOG=True
; FUNC_DEBUG=True
Я попробовал команду xargs
export $(cat file.env | sed 's/#.*//g' | xargs)
Я нашел другую реализацию
export ENV_FILE = "file.env"
if [ -f "$ENV_FILE" ]; then
echo "[INFO]: Reading $ENV_FILE file."
while IFS= read -r line; do
# Skip comments and empty lines
if [[ "$line" =~ ^\s*#.*$ || -z "$line" ]]; then
continue
fi
# Split the line into key and value
key=$(echo "$line" | cut -d '=' -f 1)
value=$(echo "$line" | cut -d '=' -f 2-)
# Remove single quotes, double quotes, and leading/trailing spaces from the value
value=$(echo "$value" | sed -e "s/^'//" -e "s/'$//" -e 's/^"//' -e 's/"$//' -e 's/^[ \t]*//;s/[ \t]*$//')
# Export the key and value as environment variables
export "$key=$value"
done < "$ENV_FILE"
echo "[DONE]: Reading $ENV_FILE file."
else
echo "[ERROR]: $ENV_FILE not found."
fi
Оба примера не очень корректно экспортируют переменные. Я плохо владею bash, не до конца понимаю, как это лучше сделать.
в первом примере при экспорте
эхо $NODE
{"v_edw2_node0001":
должно быть
'{"node0001": "127.0.0.1","node0002": "127.0.0.2","node0003": "127.0.0.3"}'
Переменные следует экспортировать, как указано, а строки, начинающиеся с символа # или ;, следует игнорировать (расценивать как комментарий).
Кроме того, если вы опустите IFS=, то встроенный read отбросит ведущие и конечные пробелы.
В вашем коде указано удалить окружающие кавычки, но в тексте говорится, что их следует оставить («$NODE должен быть ...»). Что он?





Кажется, с вашей «комплексной переменной» проблем нет. Проблема в строках комментариев, начинающихся с ;.
Удалите эти строки или замените точку с запятой на #.
После этого переменные появляются прямо в оболочке. Не нужно возиться с кавычками, поскольку они и так верны.
Если вам действительно нужны строки ;-комментариев, предварительно обработайте файл, заменив точки с запятой.
Я заменил ; символ # в файле file.new и использованном скрипте
filePath = "${1:-file.env}"
if [ ! -f "$filePath" ]; then
return 0
fi
while read -r line; do
if [[ "$line" =~ ^\s*#.*$ || -z "$line" ]]; then
continue
fi
key=$(echo "$line" | cut -d '=' -f 1 | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
value=$(echo "$line" | cut -d '=' -f 2- | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
export "$key=$value"
done < "$filePath"
вставьте свой скрипт на shellcheck.net для проверки, рекомендаций...
Если вас не волнуют предупреждения и вы используете современную версию bash (4+):
mapfile lines <file.env
export "${lines[@]}"
Или вы можете удалить строки без определения и обрезать пробелы с помощью:
mapfile defs <(
sed '
s/^[[:space:]]*//
s/[[:space:]]*=[[:space:]]*/=/
/^[a-zA-Z_]\{1,\}=/!d
s/[[:space:]]*$//
' file.env
)
export "${defs[@]}"
Если вы используете bash 3, файл карты может стать циклом чтения:
while IFS= read -r line; do
[[ $line =~ ^[[:space:]]*([a-zA-Z_]+)[[:space:]]*=[[:space:]]*((.*[^[:space:]])?)[[:space:]]*$ ]] &&
export "${BASH_REMATCH[1]}=${BASH_REMATCH[2]}"
done <file.env
Настройте регулярное выражение, если ваши переменные могут включать цифры или не должны начинаться с _ и т. д.; или если вы хотите уточнить, какие строки обрабатываются.
В вашем образце нет определений, занимающих несколько строк. Если ваши реальные данные работают, этот код не будет работать.
Если вы можете изменить файл file.env, вы можете использовать его как скрипт:
# DB
export DB_USER=test
export DB_HOST=localhost
export DB_PORT=5432
export DB_NAME=test
export NODE=$'\'{"node0001": "127.0.0.1","node0002": "127.0.0.2","node0003": "127.0.0.3"}\''
# API
export API_PORT=8081
export API_LOG=True
# export FUNC_DEBUG=True
Чтобы использовать env, просто запустите:
source file.env
Или еще проще:
. file.env
Пример результата:
~ # . /tmp/file.env
~ # env | grep -E "(NODE|DB_|API_)"
API_PORT=8081
DB_PORT=5432
DB_NAME=test
API_LOG=True
NODE='{"node0001": "127.0.0.1","node0002": "127.0.0.2","node0003": "127.0.0.3"}'
DB_HOST=localhost
DB_USER=test
~ #
Хорошо, ответ изменен, чтобы использовать $' вместо "
Эта версия env-файла не подходит (с экспортом), поскольку она также используется в скрипте Python.
grep -Ev '^(;|#|$)' file.envи попробуйте еще раз, обратите внимание: НЕ встраивайте grep в цикл оболочки jfyi.