Использование переменных внутри bash heredoc

Я пытаюсь интерполировать переменные внутри bash heredoc:

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.

Ответы

Ответ 1

В ответ на ваш первый вопрос нет замены параметров, потому что вы помещаете разделитель в кавычки - в руководстве bash говорится:

Формат здесь-документов:

      <<[-]word
              here-document
      delimiter

Нет расширения параметров, подстановки команд, арифметического расширения или расширение имени пути выполняется по слову. Если любые символы в слове цитируемый, разделитель является результатом удаления цитаты на слове, а строки в этом документе не будут расширены. Если слово без кавычек, все строки этого документа подвергаются расширению параметров, подстановке команд и арифметическому расширению. [...]

Если вы изменили свой первый пример на использование <<EOF вместо << "EOF", вы обнаружите, что он работает.

В вашем втором примере оболочка вызывает sudo только с параметром cat, и перенаправление применяется к выходу sudo cat в качестве исходного пользователя. Он будет работать, если вы попробуете:

sudo sh -c "cat > /path/to/outfile" <<EOT
my text...
EOT

Ответ 2

Не используйте кавычки с <<EOF:

var=$1
sudo tee "/path/to/outfile" > /dev/null <<EOF
Some text that contains my $var
EOF

Переменное расширение - это поведение по умолчанию внутри here-docs. Вы отключите это поведение, указав метку (с одинарными или двойными кавычками).

Ответ 3

Как поздний вывод из предыдущих ответов, вы, вероятно, окажетесь в ситуациях, когда вы хотите, чтобы некоторые, но не все переменные были интерполированы. Вы можете решить эту проблему, используя обратную косую черту, чтобы избежать знаков доллара и обратных кавычек; или вы можете поместить статический текст в переменную.

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 или "____HERE" \____HERE '____HERE' - отключит интерполяцию всех переменных и превратит '____HERE' документ в фрагмент буквального текста.