Использование переменных внутри bash heredoc - PullRequest
164 голосов
/ 08 февраля 2011

Я пытаюсь интерполировать переменные внутри 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.

Ответы [ 3 ]

224 голосов
/ 08 февраля 2011

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

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

      <<[-]word
              here-document
      delimiter

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

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

Во втором примереshell вызывает sudo только с параметром cat, и перенаправление применяется к выводу sudo cat как исходный пользователь.Это сработает, если вы попробуете:

sudo sh -c "cat > /path/to/outfile" <<EOT
my text...
EOT
85 голосов
/ 08 февраля 2011

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

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

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

12 голосов
/ 30 января 2019

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

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"
:
...