Выполнение команд bash из Rakefile [дубликат]
этот вопрос уже есть ответ здесь:
Вызов команд оболочки из Ruby
20 ответов
Я хотел бы выполнить ряд bash команды Rakefile. Моя активная оболочка bash и я буду называть rake С bash.
я включил в мой Rakefile следующий
task :hello do
%{echo "World!"}
end
но при исполнении rake hello нет выхода?
Как выполнить команды bash из Rakefile?
Примечание:это не дубликат, так как он специально спрашивает, как выполнять команды bash из Rakefile.
4 ответов:
Я думаю, что рейк хочет, чтобы это произошло с: http://rubydoc.info/gems/rake/FileUtils#sh-instance_method Пример:
task :test do sh "ls" endвстроенная функция rake sh заботится о возвращаемом значении команды (задача не выполняется, если команда имеет возвращаемое значение, отличное от 0), а также выводит выходные данные команд.
Существует несколько способов выполнения команд оболочки в Ruby. Простой (и, вероятно, самый распространенный) - использовать обратные ходы:
task :hello do `echo "World!"` endBackticks имеют хороший эффект, когда стандартный вывод команды оболочки становится возвращаемым значением. Так, например, вы можете получить вывод
lsделатьshell_dir_listing = `ls`но есть много других способов вызова команд оболочки и все они имеют преимущества/недостатки и работают по-разному. в этой статье подробно объясняет выбор, но вот краткий обзор возможностей:
stdout = %x{cmd} - альтернативный синтаксис для backticks, за кулисами он делает то же самое
exec (cmd) - полностью заменить запущенный процесс с новым процессом cmd
успех = система (cmd) - запуск подпроцесса и возврат true / false на успех / неудачу (на основе выхода cmd статус)
IO#popen (cmd) {/io/} - запустите подпроцесс и подключите stdout и stderr to io
stdin, stdout, stderr = Open3.popen3 (cmd) - запуск подпроцесса и подключение ко всем трубам (вход, выход, ошибка)
%{echo "World!"}определяет строку. Я думаю, вы хотели%x{echo "World!"}.
%x{echo "World!"}выполняет команду и возвращает вывод (stdout). Вы не увидите результата. Но вы можете сделать:puts %x{echo "World!"}есть больше способов вызвать системную команду:
- Backticks:'
system( cmd )popenOpen3#popen3
учитывая, что консенсус, похоже, предпочитает рейка
#shметод, но OP явно запрашивает bash, этот ответ может иметь некоторое использование.это актуально, так как
Rake#shиспользуетKernel#systemвызов для выполнения команд оболочки. Рубин жестко кодирует это/bin/sh, игнорируя настроенную оболочку пользователя или$SHELLв среду.вот обходной путь, который вызывает bash от
/bin/sh, что позволяет по-прежнему использоватьshспособ:task :hello_world do sh <<-EOS.strip_heredoc, {verbose: false} /bin/bash -xeuo pipefail <<'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, или, может быть, он загружается автоматически, когда вы находитесь в проекте rails, но я использовал этот внешний rails и поэтому должен был сам его защитить.
есть два heredocs, внешний с маркерами
EOSи внутренний с маркерамиBASH.способ, которым это работает, заключается в подаче внутреннего heredoc между маркерами BASH в stdin bash. Обратите внимание, что он работает в контексте
/bin/sh, так что это posix heredoc, а не ruby. Обычно для этого требуется, чтобы конечный маркер находился в столбце 1, Чего здесь нет из-за отступа.однако, потому что он завернут в рубиновый heredoc,
strip_heredocметод применяется там деиндентирует его, помещая всю левую сторону внутренний heredoc в колонке 1 до/bin/shвидя его.
/bin/shтакже обычно расширяются переменные в пределах heredoc, что может помешать скрипту. Одинарные кавычки вокруг маркера начала, 'BASH', tell/bin/shне расширять ничего внутри heredoc, прежде чем он будет передан bash./bin/shвсе еще применяет экранирование к строке перед ее передачей в bash. Это означает, что обратная косая черта побеги должны быть удвоены, чтобы сделать это через/bin/shto Баш, т. е.\становится\.параметры bash
-xeuo pipefailнеобязательны.The
-euo pipefailаргументы говорят bash работать в строгом режиме, который останавливает выполнение при любом сбое или ссылке на неопределенную переменную, даже команду в конвейере. Это вернет ошибку рейку, который остановит задачу рейка. Обычно это то, что вы хотите. Аргументы могут быть отброшены, если вы хотите нормальное поведение bash.The
-xвозможность колотить и до#shработать согласованно, так что грабли только печатает команды bash, которые на самом деле выполняются. Это полезно, если ваш скрипт не предназначен для запуска в полном объеме, например, если это был тест, который позволяет корректно завершить в начале скрипта.будьте осторожны, чтобы не установить код выхода, отличный от 0, если вы не хотите, чтобы задача rake не удалась. Обычно это означает, что вы не хотите использовать
|| exitконструирует без установки кода выхода явно, т. е.|| exit 0.если вы столкнетесь с какой-либо странностью Баш по пути, выключите
-o pipefail. Я видел немного багги, связанные с ним специально при конвейерной передаче вgrep.
Comments