Help us understand the problem. What is going on with this article?

Rakeのshで外部コマンドを実行する

More than 5 years have passed since last update.

require 'rake'するとshというメソッドが定義される。内部ではKernel.systemが使われており、Kernel.systemとよく似た振る舞いをするが、いくつかの機能が追加されている。ここではそれらの機能について解説する。

basic.rb
require 'rake'

sh "ruby -e 'puts :stdout; warn :stderr;'"
basic.rbの実行結果
ruby -e 'puts :stdout; warn :stderr;'
stdout
stderr

実行に失敗するとデフォルトでRuntimeErrorが発生する

exception.rb
require 'rake'

sh 'ruby -e "exit 1"'
exception.rbの実行結果
ruby -e "exit 1"
/home/vzvu3k6k/.anyenv/envs/rbenv/versions/2.2.0/lib/ruby/2.2.0/rake/file_utils.rb:66:in `block in create_shell_runner': Command failed with status (1): [ruby -e "fail"...] (RuntimeError)
(後略)

Kernel.system`と違い、コマンドが失敗した場合はRuntimeErrorが発生する。つまり、失敗時には勝手にタスクの実行が止まる。これによって、途中のステップが失敗したまま次の処理が実行されて意図しない結果になったり、処理が失敗したことにさえ気づかないといったトラブルを防ぐことができる。

ブロックで実行結果を受け取る

block.rb
require 'rake'

sh "ruby -e 'exit 1'" do |ok, status|
  p({ok: ok, status: status})
end

puts "例外は発生しない"
block.rbの実行結果
ruby -e 'exit 1'
{:ok=>false, :status=>#<Process::Status: pid 27598 exit 1>}
例外は発生しない

ブロックを渡すと、コマンドの実行結果(true/false)、コマンドの実行ステータス($?)を引数にして呼び出される。ブロックが渡された場合には、コマンドが失敗してもRuntimeErrorが発生しない。

オプション

引数の末尾にHashを付けることで、verbose, noopオプションを設定できる。

参考: Ruby リファレンスマニュアル - module FileUtils - オプションの説明

verbose

verboseが偽値だと実行するコマンドが表示されなくなる。

verbose.rb
require 'rake'

puts "# default"
sh "echo foobar"

puts

puts "# verbose: false"
sh "echo foobar", verbose: false
verbose.rbの実行結果
# default
echo foobar
foobar

# verbose: false
foobar

noop

noopが偽値だとコマンドが実行されなくなる。

noop.rb
require 'rake'

sh "touch dummy", noop: true # コマンドが実行されない
puts File.exist? "dummy" # ファイルが作られていないのでfalseになる

verboseとnoopを同時に設定することもできる。

verboseとnoopのデフォルト値を設定する

verboseのデフォルト値はverboseメソッドで、noopのデフォルト値はnowriteメソッドで設定できる。

この設定値はshだけではなく、FileUtilsの他のメソッドにも適用される。

verbose.rb
require 'rake'

verbose(false)
sh "表示されない" rescue nil

verbose(true) do
  sh "verboseは#{verbose}になり、表示される" rescue nil
end

sh "ブロックを抜けるとverboseは元の状態に戻るので表示されない" rescue nil
sh "オプションを直接指定すると上書き可能", verbose: true rescue nil

Kernel.systemにオプションを渡す

Kernel.systemにオプションを渡すこともできる。引数の末尾のHashはverbose, noopのオプションと解釈されることに注意。

system_options.rb
require 'rake'

begin
  sh "pwd", {chdir: "/"}
rescue
  # 末尾のHashはsystemへのオプションではなく
  # verbose, noopのオプションと解釈されるので、
  # <ArgumentError: no such option: chdir>が発生する。
  p $!
end

# systemにオプションを渡すためには
# 常に末尾にverbose, noopオプションのためのHashを付けないといけない。
sh "pwd", {chdir: "/"}, {}

そのほか

RakeはRubyを起動するrubyというメソッドも提供している。動作はshに準ずる。

Rubyで外部コマンドを実行する方法については下記を参照。

CC0

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away