Подтвердить что ты не робот

Принуждение bash для расширения переменных в строке, загруженной из файла

Я пытаюсь выяснить, как сделать bash (force?) развернуть переменные в строке (которая была загружена из файла).

У меня есть файл с именем "something.txt" с содержимым:

hello $FOO world

Затем я запустил

export FOO=42
echo $(cat something.txt)

это возвращает:

   hello $FOO world

Он не расширил $​​FOO, хотя была установлена ​​переменная. Я не могу eval или источник файла - поскольку он попытается выполнить его (он не является исполняемым, как есть), я просто хочу, чтобы строка с переменными была интерполирована).

Любые идеи?

4b9b3361

Ответ 1

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

envsubst < something.txt

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

пакет GNU gettext.

@Rockallite  - Я написал небольшую обертку script, чтобы позаботиться о проблеме "\ $".

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

Здесь мой script:

#! /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  "[email protected]"

Ответ 2

Многие ответы, использующие 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, который действительно является оболочкой script, которая просто устанавливает переменные, и template.txt, который является шаблоном, который использует эти переменные:

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

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

Ответ 3

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

echo $(eval echo $(cat something.txt))

Ответ 4

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

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

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

Ответ 5

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

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

something=$(cat something.txt)

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

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

RESULT=$(source temp.out)

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

Ответ 6

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

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

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

Ответ 7

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

  • позволяет заменять переменные, которые определены

  • оставляет неизменные переменные, которые не определены. Это особенно полезно при автоматическом развертывании.

  • поддерживает замену переменных в следующих форматах:

    ${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