module function Kernel.#spawn

spawn(command, options={}) -> Integer[permalink][rdoc][edit]
spawn(env, command, options={}) -> Integer

引数を外部コマンドとして実行しますが、生成した子プロセスの終了を待ち合わせません。生成した子プロセスのプロセスIDを返します。

引数の解釈

この形式では command が shell のメタ文字

  * ? {} [] <> () ~ & | \ $ ; ' ` " \n

を含む場合、shell 経由で実行されます。そうでなければインタプリタから直接実行されます。

[PARAM] command:
コマンドを文字列で指定します。
[PARAM] env:
更新する環境変数を表す Hash
[PARAM] options:
オプションパラメータ Hash
[EXCEPTION] Errno::EXXX:
起動に失敗し、ruby インタプリタに制御が戻った場合に発生します。
[EXCEPTION] Errno::EXXX:
コマンドが実行できなかった場合に発生します。

[SEE_ALSO] Kernel.#system,Kernel.#exec

spawn(program, *args) -> Integer[permalink][rdoc][edit]
spawn(env, program, *args, options={}) -> Integer

引数を外部コマンドとして実行しますが、生成した子プロセスの終了を待ち合わせません。生成した子プロセスのプロセスIDを返します。

env に Hash を渡すことで、exec(2) で子プロセス内でファイルを実行する前に環境変数を変更することができます。 Hash のキーは環境変数名文字列、Hash の値に設定する値とします。 nil とすることで環境変数が削除(unsetenv(3))されます。

# FOO を BAR にして BAZ を削除する
pid = spawn({"FOO"=>"BAR", "BAZ"=>nil}, command)

親プロセスは Process.#waitpid で子プロセスの終了を待ち合わせるかもしくは Process.#detach で子プロセスを切り離すかしてください。そうでないとゾンビプロセスが残る場合があります。

引数の解釈

この形式で呼び出した場合、空白や shell のメタキャラクタもそのまま program の引数に渡されます。先頭の引数が2要素の配列であった場合、第1要素の文字列が実際に起動するプログラムのパスであり、第2要素が「みせかけ」のプログラム名になります。また、第1要素はフルパスで指定しなくても環境変数 PATH から探します。

option引数の概要

Hash を options として渡すことで、起動される子プロセスの

  • プロセスグループ
  • resource limit
  • カレントディレクトリ
  • umask
  • 子プロセスでのリダイレクト

などを変更できます。環境変数のクリアなども指定できます。

以下のオプションが指定できます。

:unsetenv_others

これを true にすると、envで指定した環境変数以外をすべてクリアします。 false だとクリアしません。false がデフォルトです。

:pgroup

引数に true or 0 を渡すと新しいプロセスグループを作成し、そこで動きます。整数を渡すと、指定したプロセスグループに属します nil を渡すとプロセスグループを変更しません。デフォルトは nil です。

:rlimit_core, :rlimit_cpu, etc

resource limit を設定します。詳しくは Process.#setrlimit を見てください。引数には整数、もしくは整数2つの配列を渡します。

:chdir

指定した文字列をカレントディレクトリにします。

:umask

指定した整数を umask に設定します。

リダイレクト関連

Hash のキーに子プロセス側のファイルデスクリプタを、対応する値に親プロセス側のファイルデスクリプタやファイル名を指定することでリダイレクトを実現できます。

:close_others

これを true に設定するとリダイレクトされていない、0(stdin), 1(stdout), 2(stderr) 以外のファイルデスクリプタをすべて閉じます。 true がデフォルトです。

option引数によるリダイレクトの概要

Hash のキー(子プロセス側)には以下のいずれかが指定できます。

  • 単一のファイルデスクリプタ
  • ファイルデスクリプタの配列

配列を渡すことで複数のファイルデスクリプタを同時にリダイレクトできます。

Hash の値(親プロセス側)には以下のいずれかが指定できます。

  • 単一のファイルデスクリプタ
  • リダイレクト先のファイル名文字列
  • [リダイレクト先のファイル名文字列]、配列の要素にすることで File::Constants::RDONLY でファイルを開いてリダイレクトします。
  • [リダイレクト先のファイル名文字列, モード文字列] open(ファイル名, モード, 0644) でファイルを開いてリダイレクト します。
  • [リダイレクト先のファイル名文字列, モード文字列, パーミション(整数)] open(ファイル名, モード, パーミッション) でファイルを 開いてリダイレクトします。
  • [:child, ファイルデスクリプタ] 子プロセス側のファイルデスクリプタを指定できます。
  • :close キーで指定したファイルデスクリプタを子プロセス側で閉じます

ファイルデスクリプタを表すためには、以下が利用できます。

  • :in 標準入力, ファイルデスクリプタ0
  • :out 標準出力, ファイルデスクリプタ1
  • :err 標準エラー出力, ファイルデスクリプタ2
  • 整数 指定した整数が表すファイルデスクリプタ
  • IO IO#fileno で表されるファイルデスクリプタ

option引数の詳細および例

「:unsetenv_others」を使うと、envで指定したもの以外の環境変数をクリアします。

# すべての環境変数をクリア
pid = spawn(command, :unsetenv_others=>true)
# FOO だけ
pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true)

「:pgroup」でプロセスグループを指定できます。

# true, 0 で新しいプロセスグループを作りそのリーダーになります。
pid = spawn(command, :pgroup => true)
# 整数を渡すとそのグループに所属します。
pid = spawn(command, :pgroup => 10)

「:rlimit_core」「:rlimit_cpu」などで、resource limit を指定します。詳しくは Process.#setrlimit を見てください。このオプションには 整数 or 整数2つの配列、を渡すことができます。それぞれ Process.#setrlimit の引数が2個、3個の場合に対応します。

# 現プロセスの core の resource limit を取得
cur, max = Process.getrlimit(:CORE)
# 一時的に子プロセスの core dump を止める
pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary.
# 子プロセスで core dump を出せるようにする
pid = spawn(command, :rlimit_core=>max) # enable core dump
# 子プロセスで core dump を出せなくする
pid = spawn(command, :rlimit_core=>0) # never dump core.

「:chdir」で子プロセスのカレントディレクトリを変更できます。

pid = spawn(command, :chdir=>"/var/tmp")

「:umask」で子プロセスの umask を指定できます。

pid = spawn(command, :umask=>077)

リダイレクトは様々なやりかたが使えます。 Hash のキーが子プロセス側、値が親プロセス側です。

# 以下の例はすべて stderr を stdout にリダイレクトします
pid = spawn(command, :err=>:out)
pid = spawn(command, 2=>1)
pid = spawn(command, STDERR=>:out)
pid = spawn(command, STDERR=>STDOUT)

この例では子プロセス側の stdout には触れていないので、親プロセスから引き継がれます。

Hash の値にはファイル名も指定できます。

pid = spawn(command, :in=>"/dev/null") # read mode
pid = spawn(command, :out=>"/dev/null") # write mode
pid = spawn(command, :err=>"log") # write mode
pid = spawn(command, 3=>"/dev/null") # read mode

stdout と stderr をリダイレクトした場合は、ファイルは write mode で open されます。それ以外の場合は read mode で open されます。

ファイルのフラグ(write/read mode)やパーミッションを明示したい場合は、配列を用います。

# なにも指定がなければデフォルトで read mode が使われる。
pid = spawn(command, :in=>["file"])
# read mode で file を open し、リダイレクトする。
pid = spawn(command, :in=>["file", "r"])
# write mode で file を open し、リダイレクトする。
# パーミッションはデフォルトで 644。
pid = spawn(command, :out=>["log", "w"]) # 0644 assumed
# write mode、パーミッション 0600 でファイルをオープンし、リダイレクトする。
pid = spawn(command, :out=>["log", "w", 0600])
# flagを文字列でなくビットで指定する
pid = spawn(command, :out=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])

配列で複数のファイルデスクリプタを同時にリダイレクトできます。

# stdout と stderr を "log" ファイルにリダイレクト
pid = spawn(command, [:out, :err]=>["log", "w"])

複数のファイルデスクリプタを合わせてリダイレクトするには、 [ :child, FileDescriptor ] を使うこともできます。これは子プロセス側で FileDescriptor にリダイレクトすることを意味します。これはファイルデスクリプタを直接指定するのと異なるということに注意してください。例えば、

:err => :out

とすると、子プロセスの stderr を親プロセスの stdout にリダイレクトします。

:err => [:child, :out]

とすると、子プロセスの stderr を子プロセスの stdout にリダイレクトします。これを用いて、IO.popen で、子プロセスの stderr と stdout を混ぜる例を以下に示します。

io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]])
p io.read #=> "out\nerr\n

spawn と IO.popen ではデフォルトでは非標準的なファイルデスクリプタ(3以降)をすべて閉じます。「:close_others」オプションでこの挙動を制御できます。標準的ファイルデスクリプタ(0,1,2)は :close で明示的に閉じない限り、このオプションの影響を受けません。

「:close_others」とは無関係に ruby が open する IO にはデフォルトでは close_on_exec が設定されていて、自動的に閉じられることに注意してください。

pid = spawn(command, :close_others=>true)  # close 3,4,5,... (default)
pid = spawn(command, :close_others=>false) # don't close 3,4,5,...

これを利用して spawn を IO.popen のように使うことができます。

# similar to r = IO.popen(command)
r, w = IO.pipe
pid = spawn(command, :out=>w)   # r は子プロセスで閉じられる
w.close

「:close」を使ってファイルデスクリプタを明示的に閉じることもできます。

f = open(foo)
# f は継承されない
# system は :close_others=>false がデフォルトなのでそれ以外は継承される
system(command, f=>:close)        # don't inherit f.

spawn で特定のファイルデスクリプタだけを継承したい場合は、 io => io という形のオプションを指定します。

# valgrind は --log-fd というオプションでログの出力先を指定できます。
# これで指定したファイルデスクリプタは親プロセスから
# 子プロセスに継承されなければならないため、 log_w=>log_w とします。
log_r, log_w = IO.pipe
pid = spawn("valgrind", "--log-fd=#{log_w.fileno}", "echo", "a", log_w=>log_w)
log_w.close
p log_r.read

ファイルデスクリプタを入れ替えることもできます。

# stdout と stderr を入れ替えリダイレクト
pid = spawn(command, :out=>:err, :err=>:out)

このような相互参照を解決するため、spawnの内部で新しいファイルデスクリプタを作り、利用します。

:close_others と :close オプションが意味を持つのは、子プロセスに閉じていないファイルデスクリプタが全て渡される環境 (Unix 系統の環境)のみです。例えば Windows では元々子プロセスにはファイルデスクリプタ 0 1 2 のみ渡されるので :close_others や :close オプションは意味を持ちません。

[PARAM] env:
更新する環境変数を表す Hash
[PARAM] program:
文字列か2要素の配列を指定します。
[PARAM] args:
渡される引数です。0 個以上の文字列を指定します。
[PARAM] options:
オプションパラメータ Hash
[EXCEPTION] ArgumentError:
第一引数が配列かつ要素数が 2 でない場合に発生します。
[EXCEPTION] Errno::EXXX:
コマンドが実行できなかった場合に発生します。

[SEE_ALSO] Kernel.#system,Kernel.#exec