Використання змінних всередині bash heredoc


192

Я намагаюся інтерполювати змінні всередині баш-гередока:

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.


9
Це зрозуміла плутанина! Як зазначалося нижче, цитування будь-якої частини роздільника вимикає розширення гередока (як би воно було ''), але не цитування роздільника перетворює розширення (як би воно було ""). Однак ваша інтуїція правильна в Perl, де гередок з одноцитованим ідентифікатором поводиться так, ніби він знаходиться в одинарних лапках, один з ідентифікатором з подвійним котируванням, як у подвійних лапках, а інший з ідентифікатором, який поставлений назад, як би в задніх колах ! Дивіться: перлоп: << EOF
Нілс фон Барт

Відповіді:


252

У відповідь на ваше перше запитання заміни параметрів немає, оскільки ви поставили роздільник в лапки - інструкція з bash говорить :

Формат тут-документів:

      <<[-]word
              here-document
      delimiter

У слові не виконується розширення параметрів, підміна команд, арифметичне розширення або розширення імені шляху . Якщо будь-які символи у слові цитуються, роздільник є результатом видалення лапки на слові, а рядки в документі тут не розширюються. Якщо слово не цитується, всі рядки документа тут піддаються розширенню параметрів, підстановці команд та арифметичному розширенню. [...]

Якщо ви заміните свій перший приклад на використання <<EOFзамість, << "EOF"ви побачите, що він працює.

У вашому другому прикладі оболонка викликає sudoлише параметр cat, і перенаправлення застосовується до виводу sudo catоригіналу користувача. Він спрацює, якщо спробувати:

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

Якщо ви зацікавлені, ви можете також зробити це так: (cat > /path/to/outfile) <<EOFзамістьsudo sh -c ... <<EOF
Вольтер

Скажіть, будь ласка, похований на Баші - це вагома причина, чому це так.
Ландон Кун

96

Не використовуйте цитати з <<EOF:

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

Змінне розширення - це поведінка за замовчуванням всередині тут-документів. Ви відключаєте таку поведінку, цитуючи мітку (з одинарними або подвійними лапками).


36

Будучи пізнім наслідком попередніх відповідей тут, ви, ймовірно, опиняєтесь у ситуаціях, коли хочете, щоб деякі, але не всі змінні були інтерпольовані. Ви можете вирішити це, використовуючи зворотні косої риски, щоб уникнути знаків долара та задньої позиції; або ви можете помістити статичний текст у змінну.

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

3
Не впевнений, чому це було знято, але це додає дійсну примітку, яка не висвітлена в теперішній більш високій відповіді.
Inian
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.