Расширение строки - экранированная переменная в кавычках для значения

Для начала вот скрипт, который я запускаю, чтобы получить оскорбительную строку:

# sed finds all sourced file paths from inputted file.
#
# while reads each match output from sed to $SOURCEFILE variable.
# Each should be a file path, or a variable that represents a file path.
# Any variables found should be expanded to the full path.
#
# echo and calls are used for demonstractive purposes only 
# I intend to do something else with the path once it's expanded.

PATH_SOME_SCRIPT="/path/to/bash/script"

while read -r SOURCEFILE; do
    echo "$SOURCEFILE"
    "$SOURCEFILE"
    $SOURCEFILE
done < <(cat $PATH_SOME_SCRIPT | sed -n -e "s/^\(source\|\.\|\$include\) //p")

Вы также можете использовать следующее, чтобы проверить это как фиктивные данные:

[ /path/to/bash/script ]

#!/bin/bash
source "$HOME/bash_file"
source "$GLOBAL_VAR_SCRIPT_PATH"

echo "No cow powers here"

Для команды tl;dr в основном цикл while выдает следующее на фиктивных данных:

"$HOME/bash_file"
bash: "$HOME/bash_file": no such file or directory
bash: "$HOME/bash_file": no such file or directory
"$GLOBAL_VAR_SCRIPT_PATH"
"$GLOBAL_VAR_SCRIPT_PATH": command not found
"$GLOBAL_VAR_SCRIPT_PATH": command not found

Мой вопрос: можете ли вы правильно расширить переменную, например, напечатать «/home//bash_file» и «/expanded/variable/path»? Я также должен заявить, что хотя eval работает, я не собираюсь его использовать из-за его потенциальные небезопасности.

Подсказка, что любое значение переменной, используемое в cat | sed, будет доступно глобально, в том числе для вызывающего скрипта, а не потому, что скрипт не может вызвать значение переменной.


ПЕРВАЯ ПОПЫТКА РЕШЕНИЯ

Используя решение envsubst Анубхавы:

SOMEVARIABLE="/home/nick/.some_path"
while read -r SOURCEFILE; do 
    echo "$SOURCEFILE"
    envsubst <<< "$SOURCEFILE"; 
done < <(echo -e "\"\$SOMEVARIABLE\"\n\"$HOME/.another_file\"")

Это выводит следующее:

"$SOMEVARIABLE"
""
"/home/nick/.another_file"
"/home/nick/.another_file"

К сожалению, он не расширяет переменную! О, Боже :(


ВТОРАЯ ПОПЫТКА РЕШЕНИЯ

На основании первой попытки:

export SOMEVARIABLE="/home/nick/.some_path"
while read -r SOURCEFILE; do 
    echo "$SOURCEFILE"
    envsubst <<< "$SOURCEFILE"; 
done < <(echo -e "\"\$SOMEVARIABLE\"\n\"$HOME/.another_file\"")
unset SOMEVARIABLE

который дает нужные нам результаты без eval и без возни с глобальными переменными (в любом случае, слишком долго), ура!


Хорошие занявшие второе место были также предложены с использованием eval (хотя и потенциально небезопасного), который можно найти в этом ответе и здесь (ссылка предоставлена ​​расширенными комментариями Анубхавы).


person Nick Bull    schedule 30.06.2016    source источник
comment
Обратите внимание, если вы читали этот вопрос до этого комментария, я изменил две ошибки вывода в третьем блоке комментариев, так как они были неверными - извинения!   -  person Nick Bull    schedule 30.06.2016
comment
Спасибо за обновление вопроса со всеми соответствующими деталями и предлагаемыми ссылками +1   -  person anubhava    schedule 30.06.2016


Ответы (2)


Мой вопрос: можете ли вы правильно расширить переменную, например, напечатать "/home//bash_file" и "/expanded/variable/path"?

Да, вы можете использовать envsubst программу, которая заменяет значения переменных окружения:

while read -r sourceFile; do
   envsubst <<< "$sourceFile"
done < <(sed -n "s/^\(source\|\.\|\$include\) //p" "$PATH_SOME_SCRIPT")
person anubhava    schedule 30.06.2016
comment
Работает отлично! Спасибо за помощь - person Nick Bull; 30.06.2016
comment
Боюсь, я должен взять это обратно - это не работает на 100%. Пожалуйста, проверьте обновленный вопрос - person Nick Bull; 30.06.2016
comment
Это сработает, просто добавьте export перед объявлением вашей переменной, чтобы сделать ее доступной для среды. Так что сделай это export SOMEVARIABLE="/home/nick/.some_path" - person anubhava; 30.06.2016
comment
Ты Бог! Спасибо, а есть ли способ сделать это без их экспорта? Иногда я просто хочу, чтобы переменные были локализованы в функции. По-видимому, export local variable= является допустимым bash, но он все еще доступен вне области действия функции. - person Nick Bull; 30.06.2016
comment
Теоретически это возможно, но это решение будет лишено простоты использования envsubst. Я изучу, если это возможно, тогда я обновлю ответ. - person anubhava; 30.06.2016
comment
К сожалению, библиотека, которую мы включаем, довольно велика, а область видимости переменных раньше была проблемой из-за нелокализованных переменных. Опять же, это выходит за рамки (хех) вопроса, но ваша помощь очень ценится! - person Nick Bull; 30.06.2016
comment
Посмотрите здесь, хотя я считаю, что даже это будет небезопасно. - person anubhava; 30.06.2016
comment
Фантастическое исследование - я сталкивался с подобными решениями. Я думаю, что в целях безопасности export VARIABLE, а затем использование unset VARIABLE после завершения операций - лучший способ достичь всех целей - вопрос будет вскоре обновлен. Спасибо! - person Nick Bull; 30.06.2016

Я думаю, вы спрашиваете, как рекурсивно расширять переменные в bash. Пытаться

expanded=$(eval echo $SOURCEFILE)

внутри вашего цикла. eval запускает расширенную команду, которую вы ему даете. Поскольку $SOURCEFILE не заключено в кавычки, оно будет расширено, например, до $HOME/whatever. Затем eval расширит $HOME, прежде чем передать его echo. echo напечатает результат, а expanded=$(...) поместит распечатанный результат в $expanded.

person cxw    schedule 30.06.2016
comment
Я избегаю отрицательных голосов только потому, что не указал eval! На самом деле я знал, что этот метод работает, но eval чрезвычайно небезопасен, и его следует избегать любой ценой в качестве решения для таких сценариев, если только он не используется очень осторожно - к сожалению, в этом ответе он не использовался достаточно тщательно, чтобы считаться безопасным IMO. Пожалуйста, читайте дальше здесь: stackoverflow.com/questions/17529220/ - person Nick Bull; 30.06.2016
comment
Обратите внимание, что я обновил ответ, чтобы отразить приведенный выше комментарий - приносим извинения за то, что не сделали этого раньше. Проголосовали за правильное решение перед редактированием. - person Nick Bull; 30.06.2016