Враховуючи, що консенсус, схоже, віддає перевагу #shметоду rake , але OP явно вимагає bash, ця відповідь може мати певне значення.
Це актуально, оскільки Rake#shвикористовує Kernel#systemвиклик для запуску команд оболонки. Застосовуйте жорсткі коди Ruby /bin/sh, ігноруючи налаштовану користувачем оболонку або $SHELLв оточенні.
Ось обхідний шлях, який викликає bash з /bin/sh, дозволяючи вам як і раніше використовувати shметод:
task :hello_world do
sh <<-EOS.strip_heredoc, {verbose: false}
/bin/bash -xeu <<'BASH'
echo "Hello, world!"
BASH
EOS
end
class String
def strip_heredoc
gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, ''.freeze)
end
end
#strip_heredoc запозичено з рейок:
https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/string/strip.rb
Можливо, ви могли б отримати його, вимагаючи active_support, або, можливо, він завантажується автоматично, коли ви перебуваєте у проекті рейок, але я використовував це зовнішні рейки, і тому мені довелося його самому захищати.
Є два гередоки, зовнішній із маркерами EOSта внутрішній із маркерами BASH.
Це працює шляхом подачі внутрішнього гередоку між маркерами BASH до stdin bash. Зверніть увагу, що він працює в контексті /bin/sh, тому це posix heredoc, а не рубіновий. Зазвичай для цього потрібно, щоб кінцевий маркер знаходився у стовпці 1, що тут не так через відступ.
Однак, оскільки він загорнутий у рубіновий гередок, strip_heredocзастосований там метод робить його відступами, розміщуючи всю ліву сторону внутрішнього гередоку в стовпці 1 перед тим, /bin/shяк його побачити.
/bin/shтакож, як правило, розширює змінні всередині heredoc, що може перешкоджати сценарію. /bin/shПоодинокі лапки навколо маркера старту, 'BASH', вказують не розширювати нічого всередині heredoc, перш ніж він буде переданий bash.
Однак /bin/shвсе ще застосовує екранування до рядка перед передачею його в bash. Це означає, що екрани зворотної риски слід подвоїти, щоб пройти через /bin/shbash, тобто \стає \\.
Параметри bash -xeuнеобов’язкові.
В -euаргументах кажуть Башу працювати в суворому режимі, який зупиняє виконання за будь-якої несправності або посилань на невизначений змінний. Це поверне помилку рейку, що зупинить завдання граблі. Зазвичай, це те, що ви хочете. Аргументи можна скинути, якщо ви хочете нормальної поведінки bash.
-x bash і {verbose: false}аргумент для спільної #shроботи, так що rake друкує лише команди bash, які фактично виконуються. Це корисно, якщо ваш скрипт bash не призначений для роботи в повному обсязі, наприклад, якщо у нього є тест, який дозволяє йому вийти вишукано на початку сценарію.
Будьте обережні, не встановлюйте код виходу, відмінний від 0, якщо ви не хочете, щоб завдання граблі провалилося. Зазвичай це означає, що ви не хочете використовувати будь-які || exitконструкції без явного встановлення коду виходу, тобто || exit 0.
%{, це%x(, і це повертає stdout як рядок, замість того, щоб його друкувати.