Как сохранить переменные среды с символами новой строки в файл .env?

Вероятно, я что-то упускаю, но пытаюсь сохранить переменные среды с символами новой строки в файл .env. В идеале я хочу сделать это со всеми доступными переменными env (выходные данные env).

Возьмите эту переменную:

export MY_VAR = "Line 1
Line 2
Line 3"

Как сохранить это в файле .env, который будет выглядеть так: переменные.env

MY_VAR=Line 1\nLine2\nLine3

И как мне сделать это со всеми доступными переменными env, например, из env? Я попробовал это:

while IFS= read -r -d '' line; do
    line=$(echo -n "$line" | sed '$!s/$/\\n/' | tr -d '\n')
    echo "$line" >> variables.env
done < <(env -0)

Но это также не работает для \r.

Каков формат этого финального .env файла? Вы просто хотите, чтобы символы новой строки были закодированы как \n? Вам нужны полные строки в стиле C (включая \t, \r и т. д.)? Это формат, который где-то задокументирован? Существует множество способов кодирования текста, сохраняющих символы новой строки и другие специальные символы; будет полезно узнать, чего вы хотите, более подробно.

jwd 14.06.2024 02:43

Я думаю, вам следует для пояснения предоставить таблицу, показывающую, какие символы переменной вы хотите отобразить в какое печатное представление. Очевидно, вы хотите преобразовать шестнадцатеричный 0A в \n и, возможно, шестнадцатеричный 0D в \r. но как бы вы, например, преобразули шестнадцатеричное число 0B?

user1934428 14.06.2024 08:35

Моя цель состоит в том, чтобы проглотить его с помощью ReadInConfig() golang viper, чтобы сам файл env не мог содержать несколько строк, поскольку это нарушает правила файла .env. В идеале это все строки в стиле C, как вы сказали, jwd, но символы новой строки определенно сломают файл.

gitstackyflow 14.06.2024 17:33

Судя по комментарию @jepner к моему ответу, очевидно, что существует стандартный пакет NPM для использования файлов .env. Я не знаю, имели ли вы это в виду или вы используете это имя в более широком смысле, но вы можете взглянуть на него. npmjs.com/package/dotenv

Keith Thompson 15.06.2024 00:25
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
131
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

С env это сделать сложно. Вывод env по умолчанию принципиально неоднозначен при наличии символов новой строки. После export FOO=$'zero\nBAR=one', env выведет две строки, FOO=zero и BAR=one, которые невозможно отличить от двух переменных $FOO и $BAR.

$ export FOO=$'zero\nBAR=one' ; export BAR=one ; env | grep -e FOO -e BAR
FOO=zero
BAR=one
BAR=one
$ 

Если вы используете версию команды env GNU coreutils, у нее есть опция -0 или --null, которая заканчивает каждую строку вывода нулевым символом, а не символом новой строки. Это однозначно, поскольку имена и значения переменных среды не могут содержать нулевые символы (нулевой символ завершает строку).

env -0 > .env

Если в вашей команде env нет этой опции, вы можете написать программу (возможно, на C или Perl), которая делает то же самое.

Вы спросили о сохранении среды в файл .env. Вы не просили прочитать это потом. Вероятно, вы можете использовать bash read -r -d $'\0' для чтения строк из файла. (Я сам не совсем понял, как это работает. Вам, вероятно, придется поиграть с $IFS, чтобы избежать разделения слов.)

.env файлы не имеют той же семантики, что и оболочка, поэтому чтение их из оболочки мало чем отличается от чтения с любого другого языка: вам нужно написать правильный парсер.
chepner 14.06.2024 15:58

@chepner Есть ли какой-то стандартный формат для файлов .env? Если так, то я не знал об этом. Можете ли вы предоставить ссылку?

Keith Thompson 14.06.2024 22:30

Насколько мне известно, существует только стандарт де-факто, определяющий, как функционирует оригинальная(?) библиотека JavaScript.

chepner 14.06.2024 23:01

@chepner Хм. Я никогда об этом не слышал и не предполагаю, что ФП имеет в виду именно это. .env кажется разумным именем для файла, в котором хранится среда, не обязательно в каком-либо стандартном формате. Я оставлю комментарий по вопросу.

Keith Thompson 15.06.2024 00:24

После того, как вы сохранили env в файле (как показал @Keith Thompson), вы можете выполнить программу в этой среде примерно так:

#! /usr/bin/env python3

import subprocess
with open(".env") as file:
    env = dict(filter(lambda e:len(e)==2, map(lambda kv:tuple(kv.split(" = ")), map(bytes.decode, file.read().encode().split(b"\x00")))))
subprocess.run(["mycommand"], env=env)

Это разделение на NUL-байты и построение набора пар (ключ, значение).

Ответ принят как подходящий

Этого может быть достаточно для того, что вы пытаетесь сделать:

$ cat tst.sh
#!/usr/bin/env bash

export MY_VAR = "Line 1
Line 2
Line 3"

export MY_VAR2=17

regexp = "^[$]?'(.*)'$"
while IFS= read -r -d '' line; do
    printf -v line '%q' "$line"
    # or you could do this if your bash version is 4.4 or newer:
    #    line = "${line@Q}"
    if [[ "$line" =~ $regexp ]]; then
        line = "${BASH_REMATCH[1]}"
    fi
    printf '%s\n' "$line"
done < <(env -0)

$ ./tst.sh | grep MY_VAR
MY_VAR=Line 1\nLine 2\nLine 3
MY_VAR2=17

Это возвращает line 11: ${line@Q}: bad substitution в терминале bash.

gitstackyflow 14.06.2024 17:53

Получите новую версию bash, так как ваша очень устарела (эта функция была представлена ​​почти 10 лет назад в bash 4.4, сейчас мы работаем с bash 5.2), но я добавил альтернативный способ сделать по сути то же самое.

Ed Morton 14.06.2024 18:16

Отличный звонок — не знал, что мой vscode bash настолько устарел. Обновление исправило это, но также спасибо за версию с обратной совместимостью.

gitstackyflow 14.06.2024 20:24

Другие вопросы по теме