Принуждение bash для расширения переменных в строке, загруженной из файла
Я пытаюсь выяснить, как сделать bash (force?) развернуть переменные в строке (которая была загружена из файла).
У меня есть файл с именем "something.txt" с содержимым:
hello $FOO world
Затем я запустил
export FOO=42
echo $(cat something.txt)
это возвращает:
hello $FOO world
Он не расширил $FOO, хотя была установлена переменная. Я не могу eval или источник файла - поскольку он попытается выполнить его (он не является исполняемым, как есть), я просто хочу, чтобы строка с переменными была интерполирована).
Любые идеи?
Ответы
Ответ 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