Использование переменных внутри bash heredoc
Я пытаюсь интерполировать переменные внутри heredoc bash:
var=$1
sudo tee "/path/to/outfile" > /dev/null << "EOF"
Some text that contains my $var
EOF
Это не работает, как я ожидал ($var трактуется буквально, а не раскрывается).
Мне нужно использовать sudo tee, потому что для создания файла требуется sudo. Делать что-то вроде:
sudo cat > /path/to/outfile <<EOT
my text...
EOT
Не работает, потому что> outfile открывает файл в текущей оболочке, которая не использует sudo.
2 ответа
В ответ на ваш первый вопрос нет подстановки параметров, потому что вы поместили разделитель в кавычки - руководство по bash говорит:
Формат документов здесь:
<<[-]word here-document delimiter
Для слова не выполняется расширение параметров, подстановка команд, арифметическое расширение или расширение имени пути. Если какие-либо символы в слове заключены в кавычки, разделитель является результатом удаления кавычек в слове, а строки в документе здесь не раскрываются. Если слово не заключено в кавычки, все строки здесь-документа подвергаются расширению параметров, подстановке команд и арифметическому расширению. [...]
Если вы измените свой первый пример, чтобы использовать <<EOF
вместо << "EOF"
вы обнаружите, что это работает.
Во втором примере оболочка вызывает sudo
только с параметром cat
и перенаправление применяется к выводу sudo cat
как оригинальный пользователь. Это будет работать, если вы попробуете:
sudo sh -c "cat > /path/to/outfile" <<EOT
my text...
EOT
Не используйте кавычки с <<EOF
:
var=$1
sudo tee "/path/to/outfile" > /dev/null <<EOF
Some text that contains my $var
EOF
Расширение переменной является поведением по умолчанию внутри here-документов. Вы отключаете это поведение, заключая в кавычки (одинарные или двойные кавычки).
Как поздний вывод из предыдущих ответов, вы, вероятно, окажетесь в ситуациях, когда вы хотите, чтобы некоторые, но не все переменные были интерполированы. Вы можете решить это, используя обратную косую черту, чтобы избежать знаков доллара и обратных кавычек; или вы можете поместить статический текст в переменную.
Name='Rich Ba$tard'
dough='$$$dollars$$$'
cat <<____HERE
$Name, you can win a lot of $dough this week!
Notice that \`backticks' need escaping if you want
literal text, not `pwd`, just like in variables like
\$HOME (current value: $HOME)
____HERE
Демо: https://ideone.com/rMF2XA
Обратите внимание, что любой из механизмов цитирования - \____HERE
или же "____HERE"
или же '____HERE'
- отключит интерполяцию всех переменных и превратит документ здесь в фрагмент буквального текста.
Обычная задача - объединить локальные переменные со скриптом, который должен оцениваться другой оболочкой, языком программирования или удаленным хостом.
local=$(uname)
ssh -t remote <<:
echo "$local is the value from the host which ran the ssh command"
# Prevent here doc from expanding locally; remote won't see backslash
remote=\$(uname)
# Same here
echo "\$remote is the value from the host we ssh:ed to"
: