Принуждение 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Это решение работает даже для больших файлов.