スキップしてメイン コンテンツに移動

Rubyでプロセス管理入門

Rubyでプロセス管理入門

Ruby実践でプロセス管理を理解する

Rubyで外部コマンドを実行する際、プロセス管理は不可欠です。Process.spawnexecsystem、バックティック(``)といったメソッドは、子プロセスを生成し、入出力を制御するための基本ツールです。これらを正しく使い分けることで、スクリプトのパフォーマンスや安全性を大きく向上させることができます。

Process.spawnとexecの違い

Process.spawnは非同期で子プロセスを起動し、親プロセスはすぐに実行を継続します。戻り値として子プロセスのPIDが返ります。対してexecは現在のプロセスを置き換えて外部コマンドを実行し、親プロセスは終了します。以下に簡単な例を示します。

pid = Process.spawn('ls', '-l', '/tmp')
puts "Spawned PID: #{pid}"
# 親プロセスはここで続行

exec('ruby', '-v')
# この行以降は実行されない

Process.spawnは入出力をリダイレクトでき、非同期処理が必要な場合に便利です。execはスクリプトを外部コマンドに置き換えるため、スクリプトの残りの部分を実行したくないときに使用します。

systemとバックティックの使い分け

systemはコマンドを実行し、成功したかどうかを真偽値で返します。標準出力はそのままターミナルに表示されます。バックティックはコマンドの出力を文字列として取得します。以下のように使い分けます。

if system('mkdir', 'test_dir')
  puts 'ディレクトリ作成成功'
else
  puts '失敗'
end

output = `echo Hello, World!`
puts "バックティックで取得: #{output}"

systemは戻り値が必要な場合に、バックティックは出力内容を取得したい場合に適しています。

子プロセスの入出力共有

子プロセスと親プロセス間でデータをやり取りするには、パイプを利用します。Process.spawnin:out:err:オプションでファイルディスクリプタを指定できます。以下は標準入力からデータを渡し、標準出力を取得する例です。

stdin, stdout, stderr, wait_thr = Open3.popen3('grep', 'foo')
stdin.puts 'foo bar'
stdin.puts 'baz qux'
stdin.close

puts "出力: #{stdout.read}"
puts "エラー: #{stderr.read}"
puts "終了ステータス: #{wait_thr.value.exitstatus}"

このように、Open3を使うと入出力を細かく制御でき、非同期処理も可能です。

実践例: 外部コマンド実行と結果取得

以下は、Ruby実践でよく使われる「外部コマンド実行」シナリオです。Process.spawnで非同期にコマンドを走らせ、Open3で結果を取得し、エラーハンドリングを行います。

require 'open3'

cmd = ['git', 'status']
pid = Process.spawn(*cmd, out: :pipe, err: :pipe)
stdout, stderr, wait_thr = Process.wait2(pid)

if wait_thr.success?
  puts "Gitステータス:\n#{stdout}"
else
  warn "エラー発生:\n#{stderr}"
end

このパターンはCI/CDスクリプトやデプロイツールで頻繁に利用されます。子プロセスの入出力共有を正しく扱うことで、スクリプトの可読性と保守性が向上します。

この記事はAIによって作成されました。

コメント