Подтвердить что ты не робот

Выполнять команды bash из файла Rakefile

Я хотел бы выполнить ряд команд bash из Rakefile.

Я попробовал следующее в моем Rakefile

task :hello do
  %{echo "World!"}
end

но при выполнении rake hello нет выхода? Как мне выполнить команды bash из Rakefile?

ПРИМЕЧАНИЕ. Это не дубликат, поскольку в нем конкретно спрашивается, как выполнять команды bash из файла Rakefile.

4b9b3361

Ответ 1

Я думаю, что рейк хочет, чтобы это произошло: http://rubydoc.info/gems/rake/FileUtils#sh-instance_method Пример:

task :test do
  sh "ls"
end

Встроенная функция rake sh берет на себя возвратное значение команды (задача не работает, если команда имеет возвращаемое значение, отличное от 0) и, кроме того, она также выводит выходные команды.

Ответ 2

Существует несколько способов выполнения команд оболочки в ruby. Простой (и, вероятно, самый распространенный) - использование обратных ссылок:

task :hello do
  `echo "World!"`
end

Backticks имеют хороший эффект, когда стандартный вывод команды оболочки становится возвращаемым значением. Так, например, вы можете получить вывод ls, выполнив

shell_dir_listing = `ls`

Но есть много других способов вызвать команды оболочки, и все они имеют преимущества/недостатки и работают по-другому. В этой статье подробно объясняется выбор, но здесь есть краткие возможности:

  • stdout =% x {cmd} - Альтернативный синтаксис для обратных шагов, за кулисами он делает то же самое

  • exec (cmd) - Полностью замените запущенный процесс новым процессом cmd

  • success = system (cmd) - Запустите подпроцесс и верните true/false по успеху/сбою (в зависимости от статуса выхода cmd)

  • IO # popen (cmd) {| io | } - Запустите подпроцесс и подключите стандартный вывод и stderr to io

  • stdin, stdout, stderr = Open3.popen3 (cmd) - Запустите подпроцесс и подключаться ко всем трубам (в, из, ошибочно)

Ответ 3

%{echo "World!"} определяет строку. Я ожидаю, что вы захотите %x{echo "World!"}.

%x{echo "World!"} выполняет команду и возвращает результат (stdout). Вы не увидите результат. Но вы можете:

puts %x{echo "World!"}

Существует несколько способов вызова системной команды:

  • Backticks: `
  • system( cmd )
  • popen
  • Open3#popen3

Ответ 4

Учитывая, что консенсус, похоже, предпочитает метод rake #sh, но OP явно запрашивает bash, этот ответ может иметь некоторое применение.

Это актуально, так как Rake#sh использует вызов Kernel#system для запуска команд оболочки. Ruby hardcodes на /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, но я использовал внешние рельсы и поэтому должен был сам его определить.

Есть два heredocs, внешний с маркерами EOS и внутренний с маркерами BASH.

Как это работает, путем подачи внутреннего heredoc между маркерами bash на bash stdin. Обратите внимание, что он работает в контексте /bin/sh, поэтому он не может быть рубиновым. Обычно это требует, чтобы конечный маркер находился в столбце 1, что здесь не так из-за отступов.

Однако, поскольку он обернут в рубиновый heredoc, применяемый там метод strip_heredoc деиндентирует его, помещая его в левую часть внутреннего heredoc в столбце 1 до /bin/sh, видя его.

/bin/sh также обычно расширяет переменные в heredoc, что может помешать script. Одиночные кавычки вокруг маркера начала, 'BASH', сообщите /bin/sh, чтобы не расширять что-либо внутри heredoc, прежде чем он будет передан в bash.

Однако /bin/sh все еще применяет escape-строки к строке перед передачей ее в bash. Это означает, что пробелы обратной косой черты должны быть удвоены, чтобы пройти через /bin/sh до bash, т.е. \ становится \\.

Параметры bash -xeuo pipefail являются необязательными.

Аргументы -euo pipefail указывают bash работать в строгом режиме, который прекращает выполнение при любой ошибке или ссылается на переменную undefined, даже на команду в конвейере. Это вернет ошибку для грабли, что остановит задачу рейка. Обычно это то, что вы хотите. Аргументы можно отбросить, если вы хотите нормальное поведение bash.

Параметр -x для аргументов bash и {verbose: false} для #sh работает согласованно, так что rake выводит только команды bash, которые фактически выполняются. Это полезно, если ваш bash script не предназначен для запуска целиком, например, если у него есть тест, который позволяет ему изящно выйти в начале script.

Будьте осторожны, чтобы не установить код выхода, отличный от 0, если вы не хотите, чтобы задача рейка завершилась с ошибкой. Обычно это означает, что вы не хотите использовать какие-либо конструкторы || exit, не устанавливая явно код выхода, т.е. || exit 0.

Если вы столкнетесь с какой-либо странностью bash по пути, отключите -o pipefail. Я видел, что это связано с ошибкой, особенно при конвейерной обработке до grep.

Ответ 5

Есть два способа:

sh " expr "

или же

%x( expr )

Имейте в виду, что (expr) может быть {expr}, | expr | или "expr"

Разница в том, что sh "expr" - это метод ruby для выполнения чего-либо, а% x (expr) - встроенный метод ruby. Результат и действие разные. Вот пример

task :default do
value = sh "echo hello"
puts value
value = %x(echo world)
puts value
end

получить:

hello  # from sh "echo hello"
true   # from puts value
world  # from puts value

Вы можете видеть, что %x( expr ) будет выполнять только expr оболочки, но стандартный вывод не будет отображаться на экране. Итак, вам лучше использовать %x( expr ) когда вам нужен результат команды.

Но если вы просто хотите выполнить команду оболочки, я рекомендую использовать sh "expr". Потому что sh "irb" заставит вас войти в оболочку irb, а %x(irb) умрет.