pockestrap

Programmer's memo

Rubyの外部コマンド実行入門について発表しました

福岡Rubyist会議03で、「外部コマンド実行入門」というタイトルで発表をしました。
この記事では、登壇の背景や今後について書きたいと思います。

(福岡Rubyist会議に登壇しました(します) - pockestrap という記事で「この記事は登壇後に編集し、登壇報告記事になります。」と書いたのですが、この記事を直接編集してしまうとこの記事へのツイートとかが微妙な感じになってしまうなーと思ったので、新しく記事を書くことにしました。)

登壇資料

今回の発表では、スライドと「コマンドの選び方フローチャート」を使用しました。両方ともPDFで公開しています。

スライド

フローチャート

補足など

発表時に話したりなかったことや、質疑応答で出てきたことなどを少し書きます。

openメソッドについて

質疑応答で、nagachikaさん1から「Kernel.#openメソッドでファイルを開こうとすることの危険性」についてのお話がありました。それについて少し詳しく書こうと思います。

今回のトークでは時間の都合上ほとんど触れなかったのですが、Kernel.#openメソッドでも外部コマンドを実行できます。 https://docs.ruby-lang.org/ja/latest/method/Kernel/m/open.html
メソッドの引数に、|始まりの文字列を渡すことで、コマンドが実行できます。たとえばlsコマンドの出力結果を得るには次のように書けます。

str = open('| ls').read

ところで、Kernel.#open|始まりでない文字列を受け取ると、それをファイルパスとみなしてファイルを開きます。

# /etc/hosts を読み出す
str = open('/etc/hosts').read

しかし、ファイルを読み出すためにKernel.#openを使うのは危険です。もしこのパスをユーザーが自由に指定できる場合、悪意のあるユーザーが|始まりの文字列を送りつけることで、意図しないコマンド実行が可能となってしまいます。

# これはファイルを読み出すだけなので問題ない
filepath_from_user_input = '/path/to/file'
open(filepath_from_user_input).read

# ファイルを読み込むことを意図していたはずが、マシンがrebootしてしまう!
filepath_from_user_input = '| reboot'
open(filepath_from_user_input).read

そのためファイルをopenしたいだけであれば、次のようにKernel.#openではなくFile.openを使いましょう。

# これならrebootしない
filepath_from_user_input = '| reboot'
File.open(filepath_from_user_input).read

またopen-uriライブラリを使っている場合もKernel.#openを使ってURLを開こうとすると同様の問題があるため注意が必要です。代わりにURI(uri).open()などを使用しましょう。

spawnの引数

今回のトークではspawnを始めとする各メソッドが共通で受け取る引数の説明をかんたんにしました。 https://docs.ruby-lang.org/ja/latest/method/Kernel/m/spawn.html

spawnなどが受け取る引数は多く、発表内では(登壇と準備の)時間の都合上、ごくごく一部のみしか触れることができませんでした。

これらについても詳しく解説ができると良いなあと思っています。時間さえあれば…

参考文献

今回の発表では飛ばしてしまったのですが、スライドの最後に参考文献を簡単に書いていました。

その中でもakrさんの Open3のはなし は特におすすめです。Open3モジュールの設計について詳しく解説がされています。今回のトークでは「どれをどう使うか」という話にフォーカスしましたが、今回紹介したメソッドの設計をより詳しく知りたい場合には、この資料を当たることをおすすめします。

登壇の背景

色々な方に「どうしてこのテーマで話すことにしたのか」と聞かれたので、ここでもかんたんに触れておこうと思います。

外部コマンドの実行の仕方については、以前からいい感じのドキュメントの少なさを感じていました。今回特に重視していた「どうメソッドを選ぶか」という話には、決定版と言えるようなドキュメントはなかったと思います。そのような状況はとくに初心者にとって優しくないですし、改善したいなとずっと思っていました。

今回福岡Rubyist会議でこのテーマを選んだこと自体には特に深い理由はなく、「ずっとやろうやろうと思っていた話だし、いい加減重い腰を上げて取り組むべきか…」と思い立ってこのテーマでプロポーザルを出しました。

今後について

プロポーザルにも書いたのですが、この発表は今回のトークだけで終えず、長い期間参照されるドキュメントを最終的には作りたいと思っています。具体的には、発表中につかったフローチャートをより良い形で公開したいと思っています。

今日のznzさんの発表にあったようにるびまでも良いですし、もしくはるりまやruby本体のRDocでも良いかも知れません。 内容的に、自分のブログよりはオフィシャル色の強いところに置きたい気持ちがあります。そしてググって見つかるようなところに置きたい気持ちもあります。

今回発表で使ったフローチャートはmiroを使って雑に作ったものなのですが、もっときれいな形でビジュアライズできたりしないかなという気持ちもあります。

このあたりに関して良いアイディアがある方がいれば、気軽に声をかけていただけると嬉しいです。るりまのページを1つ作って、それをRDocに展開していくとかがやりやすいかなあ…。


Twitterでの反応を見ている限りだと、特にフローチャートが思っていたよりも好評でした。今回のトークで一番気に入っている部分でもあり、ずっとやりたいと思っていたことが受け入れられて嬉しかったです。


  1. 直接お話したことがないので本当にnagachikaさんだったか実は確信が持てていないのですが、あってるかな?