Принуждение bash к расширению переменных в строке, загруженной из файла
Я пытаюсь понять, как сделать bash (force?) разверните переменные в строке (которая была загружена из файла).
у меня есть файл с названием "Что-то.txt" с содержание:
hello $FOO world
Я тогда бегу
export FOO=42
echo $(cat something.txt)
возвращает:
hello $FOO world
он не расширил $FOO, хотя переменная была установлена. Я не могу eval или источник файла - как он будет пытаться выполнить его (это не исполняемый файл, как это - я просто хочу строку с переменными интерполированный.)
какие идеи?
12 ответов:
я наткнулся на то, что я думаю, что ответ на этот вопрос:.
envsubst < something.txt
если он еще не доступен в вашем дистрибутиве, он находится в
пакет GNU
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 [[ = -h ]] ;then echo -e >&2 "$Usage" ; exit 1 ;fi if [[ = -sl ]] ;then sl='\' ; shift ;fi sed 's/\$/${EnVsUbDolR}/g' | EnVsUbDolR=$sl$ envsubst "$@"
многие ответы с помощью
eval
иecho
вид работы, но перерыв на различные вещи, такие как несколько строк, пытаясь избежать оболочки мета-символов, убегает внутри шаблона не предназначен для расширения bash и т.д.у меня была такая же проблема, и я написал эту функцию оболочки, которая, насколько я могу судить, обрабатывает все правильно. Это по-прежнему будет удалять только конечные новые строки из шаблона из-за правил замены команд bash, но я никогда обнаружил, что это проблема, пока все остальное остается нетронутым.
apply_shell_expansion() { declare file="" 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
на практике я использую это как своего рода легкий шаблон системы.
вы не хотите печатать каждую строку, вы хотите оценить это так, что Bash может выполнять переменные замены.
FOO=42 while read; do eval echo "$REPLY" done < something.txt
посмотреть
help eval
или руководство по Bash для получения дополнительной информации.
другой подход (который кажется неприглядным, но я все равно ставлю его здесь):
написать содержание чего-то.txt к временному файлу, с Эхо-заявлением, обернутым вокруг него:
something=$(cat something.txt) echo "echo \"" > temp.out echo "$something" >> temp.out echo "\"" >> temp.out
затем верните его обратно в переменную:
RESULT=$(source temp.out)
и $результат будет иметь все это расширено. Но это кажется таким неправильным !
Если вы только хотите, чтобы ссылки на переменные были расширены (цель, которую я имел для себя), вы можете сделать следующее.
contents="$(cat something.txt)" echo $(eval echo \"$contents\")
(экранированные кавычки вокруг $contents являются ключевыми здесь)
следующее решение:
позволяет заменить переменные, которые определены
оставляет неизменными переменные заполнители, которые не определены. Это особенно полезно при автоматизированном развертывании.
поддерживает замену переменных в следующих форматах:
${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
bash
метод (однострочный вариант ответ Майкла Нила), используя процесс & команду:FOO=42 . <(echo -e echo $(<something.txt))
выход:
hello 42 world
отметим, что
export
не требуется.GNU
sed
оценить способ, если что-то.txt много строк:FOO=42 sed 's/"/\\"/g;s/.*/echo "&"/e' something.txt
$ 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.
envsubst
- отличное решение (см. ответ LenW), если контент, который вы заменяете, имеет "разумную" длину.в моем случае мне нужно было заменить содержимое файла, чтобы заменить имя переменной.
envsubst
требуется, чтобы содержимое экспортировалось как переменные среды, и bash имеет проблему при экспорте переменных среды, которые больше мегабайта или около того.awk solution
используя cuonglm решение от a другой вопрос:
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
Это решение работает даже для больших файлов.