Избегайте eval при использовании переменных среды в файле конфигурации [duplicate]

Для тех, кто задается вопросом, куда должен идти файл службы Firebase Admin SDK serviceAccountKey.json. Просто поместите его в папку функций и разверните, как обычно.

Это все еще озадачивает меня, почему мы не можем просто получить URL-адрес загрузки из метаданных, как в Javascript SDK. Создание URL-адреса, которое в конечном итоге истечет и сохранить его в базе данных, нежелательно.

55
задан Michael Neale 21 May 2012 в 11:13
поделиться

11 ответов

Я наткнулся на то, что, по моему мнению, является ответом на этот вопрос: команда envsubst.

envsubst < something.txt

Если он еще не доступен в вашем дистрибутиве, он находится в

GNU package gettext.

@Rockallite - я написал небольшой скрипт-оболочку, чтобы позаботиться о проблеме «\ $».

(Кстати, есть функция "envsubst, объясненный в https://unix.stackexchange.com/a/294400/7088 для расширения только некоторых переменных на входе, но я согласен, что избежать исключений гораздо удобнее .)

Вот мой скрипт:

#! /bin/bash
      ## -*-Shell-Script-*-
CmdName=${0##*/}
Usage="usage: $CmdName runs envsubst, but allows '\$' to  keep variables from
    being expanded.
  With option   -sl   '\$' keeps the back-slash.
  Default is to replace  '\$' with '$'
"

if [[ $1 = -h ]]  ;then echo -e >&2  "$Usage" ; exit 1 ;fi
if [[ $1 = -sl ]] ;then  sl='\'  ; shift ;fi

sed 's/\\\$/\${EnVsUbDolR}/g' |  EnVsUbDolR=$sl\$  envsubst  "$@"
62
ответ дан LenW 24 August 2018 в 08:54
поделиться
  1. bash метод (один вариант ответа Майкл Нил ), используя process & amp; command substitution :
    FOO=42 . <(echo -e echo $(<something.txt))
    
    Выход:
    hello 42 world
    
    Обратите внимание, что export не требуется.
  2. GNU sed оценить , если something.txt имеет много строк:
    FOO=42 sed 's/"/\\\"/g;s/.*/echo "&"/e' something.txt
    
0
ответ дан agc 24 August 2018 в 08:54
поделиться

Следующее решение:

  • позволяет заменять переменные, которые определены
  • оставляет неизмененные переменные заполнителями, которые не определены. Это особенно полезно при автоматическом развертывании.
  • поддерживает замену переменных в следующих форматах: ${var_NAME} $var_NAME
  • сообщает, какие переменные не определены в среде и возвращает код ошибки для таких случаев


    TARGET_FILE=someFile.txt;
    ERR_CNT=0;

    for VARNAME in $(grep -P -o -e '\$[\{]?(\w+)*[\}]?' ${TARGET_FILE} | sort -u); do     
      VAR_VALUE=${!VARNAME};
      VARNAME2=$(echo $VARNAME| sed -e 's|^\${||g' -e 's|}$||g' -e 's|^\$||g' );
      VAR_VALUE2=${!VARNAME2};

      if [ "xxx" = "xxx$VAR_VALUE2" ]; then
         echo "$VARNAME is undefined ";
         ERR_CNT=$((ERR_CNT+1));
      else
         echo "replacing $VARNAME with $VAR_VALUE2" ;
         sed -i "s|$VARNAME|$VAR_VALUE2|g" ${TARGET_FILE}; 
      fi      
    done

    if [ ${ERR_CNT} -gt 0 ]; then
        echo "Found $ERR_CNT undefined environment variables";
        exit 1 
    fi
0
ответ дан aprodan 24 August 2018 в 08:54
поделиться
$ eval echo $(cat something.txt)
hello 42 world
$ bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)
Copyright (C) 2007 Free Software Foundation, Inc.
0
ответ дан ClearCrescendo 24 August 2018 в 08:54
поделиться

Следующие работы: bash -c "echo \"$(cat something.txt)"\"

-1
ответ дан IKavanagh 24 August 2018 в 08:54
поделиться

envsubst - отличное решение (см. ответ LenW), если содержимое, которое вы заменяете, имеет «разумную» длину.

В моем случае мне нужно было заменить содержимое файла, чтобы заменить имя переменной. envsubst требует, чтобы содержимое экспортировалось как переменные среды, а bash - при экспорте переменных окружения размером более мегабайта.

awk solution

Использование cuonglm's solution из другого вопроса:

needle="doc1_base64" # The "variable name" in the file. (A $ is not needed.)
needle_file="doc1_base64.txt" # Will be substituted for the needle 
haystack=$requestfile1 # File containing the needle
out=$requestfile2
awk "BEGIN{getline l < \"${needle_file}\"}/${needle}/{gsub(\"${needle}\",l)}1" $haystack > $out

Это решение работает даже для больших файлов.

0
ответ дан Larry K 24 August 2018 в 08:54
поделиться

Другой подход (который кажется icky, но я все равно помещаю его сюда):

Запишите содержимое something.txt в файл temp с инструкцией эха, обернутой вокруг него:

something=$(cat something.txt)

echo "echo \"" > temp.out
echo "$something" >> temp.out
echo "\"" >> temp.out

затем верните его обратно в переменную:

RESULT=$(source temp.out)

, а $ RESULT будет расширена. Но это кажется неправильным!

4
ответ дан Michael Neale 24 August 2018 в 08:54
поделиться

вы можете попробовать

echo $(eval echo $(cat something.txt))
15
ответ дан pizza 24 August 2018 в 08:54
поделиться

Если вы хотите, чтобы ссылки на переменные были расширены (цель, которую я имел для себя), вы могли бы сделать следующее.

contents="$(cat something.txt)"
echo $(eval echo \"$contents\")

(Кэшированные цитаты вокруг $ содержимого здесь являются ключевыми)

1
ответ дан SS781 24 August 2018 в 08:54
поделиться

Вы не хотите печатать каждую строку, вы хотите оценить так, чтобы Bash мог выполнять подстановки переменных.

FOO=42
while read; do
    eval echo "$REPLY"
done < something.txt

См. help eval или Bash руководство для получения дополнительной информации.

10
ответ дан Todd A. Jacobs 24 August 2018 в 08:54
поделиться

Многие ответы с использованием работы eval и echo, но разрываются на разные вещи, такие как несколько строк, пытаясь избежать метасимволов оболочки, исчезают внутри шаблона, не предназначенного для расширения bash, и т. д.

У меня была такая же проблема, и я написал эту функцию оболочки, которая, насколько я могу судить, обрабатывает все правильно. Это все равно будет вытеснять только последние строки из шаблона из-за правил подстановки команд bash, но я никогда не обнаружил, что это проблема, если все остальное остается неповрежденным.

apply_shell_expansion() {
    declare file="$1"
    declare data=$(< "$file")
    declare delimiter="__apply_shell_expansion_delimiter__"
    declare command="cat <<$delimiter"$'\n'"$data"$'\n'"$delimiter"
    eval "$command"
}

Например, вы можете использовать его как это с помощью parameters.cfg, который действительно является скриптом оболочки, который просто устанавливает переменные, и template.txt, который является шаблоном, который использует эти переменные:

. parameters.cfg
printf "%s\n" "$(apply_shell_expansion template.txt)" > result.txt

На практике I используйте это как своего рода легкую систему шаблонов.

24
ответ дан wjl 24 August 2018 в 08:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: