Rubyでプロセス管理入門
Ruby実践でプロセス管理を理解する
Rubyで外部コマンドを実行する際、プロセス管理は不可欠です。Process.spawn、exec、system、バックティック(``)といったメソッドは、子プロセスを生成し、入出力を制御するための基本ツールです。これらを正しく使い分けることで、スクリプトのパフォーマンスや安全性を大きく向上させることができます。
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.spawnのin:、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スクリプトやデプロイツールで頻繁に利用されます。子プロセスの入出力共有を正しく扱うことで、スクリプトの可読性と保守性が向上します。
コメント
コメントを投稿