読者です 読者をやめる 読者になる 読者になる

bekkou68の日記

開発しているサービス, IT技術, 英語など。

『Working with Unix Processes』の Spawning Terminal Processes を読みました

Unix 勉強会

はじめに

Daemon Processes』の続きです。

勉強会でのまとめ

本文の自分の理解のまとめ、本文の知識をもって試したこと、議論したこと、自分の理解のための補足などを書きます。

イントロダクション

Rubyプログラムからシェルのコマンドを実行する方法には以下のものがある。

exec
  • ブロッキング
  • メソッドを呼び出したそのプロセスでコマンドを実行する
  • exec 後に処理を書いても実行されないことに注意
    • fork と組み合わせることでシンプルにコマンドを呼べる
  • exec はファイルディスクリプタをデフォルトではクローズしないことに注意
    • その性質をもちいて、たとえば Rubyプロセスでファイルを開いて、Pythonプロセスにファイルディスクリプタを渡して read するとファイルの内容を読むことができる
    • つまりファイルを開き直す必要がない
  • 本文中には「デフォルトで」とあったのでファイルディスクリプタをクローズするオプションはあるのかと思って調べてみたけどなさそうだった
  • OSコマンドインジェクションを防ぐためには文字列でなく配列で渡す
    • 配列で渡すと空白を含めなくなるのでインジェクションされにくくなる
Kernel#system
  • ブロッキング。後続の処理は実行される
  • 戻り値はコマンド実行後の exit code が 0 なら true で 0以外なら false
  • コマンドの実行結果はターミナルに表示される
Kernel#` もしくは %x[]
  • ブロッキング。後続の処理は実行される
  • 戻り値には結果が文字列として返る
  • コマンドの結果をプログラムで処理したい場合に使えそう
Process.spawn
  • ノンブロッキング。後続の処理は実行される
  • あえてブロックにしたければ戻り値の pid を wait すればいい
  • オプションで STDERR => STDOUT などとリダイレクトできる

Rubyプロセスを wait することは今までやってきたが、spawn した"ターミナルプロセス"も wait できる。Unix の柔軟性!

蛇足ですが、コマンド実行時の標準出力・標準エラーのリダイレクトの書き方ををよくわすれるので書いておきます。

$ ls --help 1>>suc.log 2>>err.log # 追記
$ ls --help 1>suc.log 2>err.log   # 上書き

これに関してはこちらの記事『UNIXの部屋 コマンド検索:リダイレクト (*BSD/Linux)』がとても詳しいです。

IO.popen
  • ブロッキング。popenブロックを書かないとコマンドが実行されないようだ
  • popenブロック内でそのパイプのストリームにアクセスできる
Open3.popen3

STDIN, STDOUT, STDERR すべてにアクセスできる。

以下、本文中のサンプルコードを試してうまくいかなかった。`:err => :out` の部分の仕様が変わったのかな。。

  # 実行した環境では `ls --help` するとそのようなオプションは無いとエラーが起きる
  # オプションで標準エラーを標準出力にリダイレクトして表示されることを期待している
  Open3.popen3('ls', '--help', :err => :out) {|stdin, stdout, stderr|
    puts stdout.read # なぜか表示されなかった
    puts stderr.read # こっちは表示された
  }

調べていたら popen4 というのも見つけた。

まとめ

これらのメソッドは fork を用いて実現されている。そのためメモリを丸々コピーする fork のコストは考慮すること。Ruby で fork のコストをかけずに shell out する方法はコアライブラリーではサポートしていない。posix-spawn プロジェクトでは低コストで shell out する方法をサポートしている。
https://github.com/rtomayko/posix-spawn
なぜ posix_spawn が早いのかというと、ファイルディスクリプタのコピーだけしか保持しないため。fork はそれに加えてメモリもコピーするのでその分重い。

フレーズ

  • Voila!: ほら見てごらん!
  • underneath: 裏では
  • drawback: 不都合
  • incur: (良くないものを)こうむる
  • discerning attributes: シャープな(聡明な)引数(カッコイイ引数。引数のことを褒めてる表現だと思う)
  • shell out: シェルアウト。Unix の用語みたい。プログラム内でコマンドを実行すること(だと思う)