Rubyには外部コマンドを実行するための機能が幾つも用意されています。しかし、それらの使い方は同じではありません。Rubyのプログラムの中で外部コマンドの実行結果を利用したい場合は、適切な方法を選択することが必要です。今回はRubyの外部コマンドの実行方法の種類と、その使い方を解説します。
外部コマンドの実行とは
今回扱う外部コマンドの実行とは、Rubyのプログラムの中からOSに付属したコマンドなどを実行することです。そして、これを実現する機能は、サーバーOSを管理するためのRubyスクリプトなどでよく使われます。まずは外部コマンドの実行とはどういうことかについて解説します。
外部コマンドを実行する方法
Rubyを含むプログラミング言語の機能を組み合わせれば、OSに付属しているコマンドと同じ機能を作ることが可能です。しかし、OSに付属しているコマンドがあるのに、わざわざ同じ機能を作るのは無駄だと言えます。なぜなら、プログラムの中からOSに付属しているコマンドを実行して結果を受け取り、それを処理に使えれば済む話です。
多くのプログラミング言語には、このような用途のために外部プログラムを実行する機能が用意されています。そして、Rubyでも外部コマンドの実行が可能です。
外部コマンドとの通信が必要
プログラムの中から外部コマンドで実行した結果を受け取るには、特別な処理を用います。例えばコマンドラインから2つのコマンドを連続で実行するケースを考えてみてください。単純に2つのコマンドを実行すると、当然その結果は別々に表示されます
ただし、コマンドラインにはパイプラインという機能があり、あるコマンドの結果を次のコマンドに入力することが可能です。
パイプラインで2つのコマンドを実行する例
$ ls -1 /var/log/syslog* | wc -l
同じようにプログラムから外部コマンドを実行してその結果を受け取るには、コマンドラインのパイプラインに相当する機能が必要です。Rubyには、外部コマンドを実行するだけの機能と、パイプラインのように外部コマンドの結果を受け取る機能とが用意されているのでうまく使い分けてください。
Rubyによる外部コマンド実行方法
先ほど紹介したように、Rubyには外部コマンドを実行するための方法が複数用意されています。ただし、外部コマンドを実行したからと言って、全ての方法でその結果を受け取れるとは限りません。また、外部コマンドの実行でエラーが発生した場合の対応も、それぞれ違います。
まずはRubyの外部コマンドを実行する方法と、その特徴について簡単に紹介します。
Kernelクラスのメソッドを使う
RubyのKernelクラスに含まれるsystemメソッドとexecメソッドを利用することで、外部コマンドの実行が可能です。使い方は外部コマンドのコマンド名とオプションを記述した文字列を用意し、それを引数で指定します。
systemメソッドとexecメソッドの実行例
commad = "/usr/bin/systemctl start https" rep = system(commad) commad = "/usr/bin/systemctl restart https" exec(command)
ただし、この方法は外部コマンドが標準出力に出力した結果を、プログラムに取り込むことはできません。そしてsystemメソッドはその戻り値で外部コマンドがエラーになったことが解りますが、execは完全に別に実行されます。
バックスラッシュ記法または%記法を使う
Rubyにはバックスラッシュで文字列を囲うとその文字列を外部コマンドとして実行する機能があり、バックスラッシュ記法と呼ばれます。また、%x()の()内に外部コマンドを指定することで、その実行が可能です。そして%xを使う方法は%記法と呼ばれます。
バックスラッシュ記法の例
result = `date` p result
%記法による外部コマンドの例
result = %x(date) p result
この方法はどちらもコマンドの標準出力を戻り値として取り込むことが可能です。ただし外部コマンドでエラーが発生した場合、その標準エラーへの出力を取得する機能はありません。
Open3クラスを使う方法
Rubyには、外部コマンドを実行する機能をまとめた標準ライブラリのOpen3が用意されています。そしてOpen3クラスのメソッドを利用することで、外部コマンドに値を渡したり、結果を受け取り、さらにエラーメッセージを受けとることが可能です。
なおOpen3クラスを利用するには、「require “open3″」が必要です。そして、単純にコマンドを実行して、その結果を受け取るだけなら、Open3.capture3メソッドを利用してください。また、外部コマンドを通信する特殊なケースではOpen3.popen3を利用します。
Open3.capture3メソッドの文法
Open3.capture3( 実行したいコマンド )
戻り値:実行結果, エラーメッセージ, ステータス
Open3.capture3メソッドによる外部コマンドの使用例
require "open3" stdout, stderr, status = Open3.capture3("ls -1") files = stdout.split("\n")
外部コマンドの実行例
Rubyの外部コマンドを実行するための機能について紹介しましたが、次からその機能を用いた具体的なプログラム例を紹介します。
バックスラッシュ記法を使う
通常、Rubyで外部コマンドの実行結果を簡単に利用したい場合は、バックスラッシュ記法を使います。なお、バックスラッシュ記法は、実行したいコマンドをバックスラッシュ(`)で囲む書き方ですが、次のように#{}による式展開を利用することで、文字列に格納したコマンドを実行させることも可能です。
式展開を利用したバックスラッシュ記法の例
cmd = "/bin/ls -1 | wc -w" file_count = `#{cmd}` puts "ファイル数: " + file_count
IO.popenを使った例
先ほどバックスラッシュ記法の例を紹介しましたが、バックスラッシュ記法は実行したコマンドのエラーメッセージを受け取れません。エラーメッセージを受け取りたい場合は、IO.popenを使います。
下記の例は、grepコマンドで/var/log/syslogを検索した結果を表示するRubyのスクリプトです。なお「:err=>[:child, :out]」オプションを指定しているので、エラーも受け取れます。そのため、もし、grepコマンドが失敗した場合は、そのメッセージを表示します。
IO.popenを使いgrepコマンドの結果を表示する例
require 'date' date = DateTime.now today = date.strftime("%b %m %d") cmd = "grep \"" + today + "\" /var/log/syslog" result = IO.popen(cmd, :err=>[:child, :out]) {|ls_io| ls_io.read } syslog = result.split("\n") syslog.each {|line| puts line }
まとめ
Ruby on RailsでWebシステムを作る仕事をされている方が外部コマンドを利用するケースは少ないかもしれません。しかしRubyはサーバー管理の自動化用プログラム作成にも利用されています。そしてそのような用途では、ゼロから機能を作るよりもOS付属のコマンドを利用すれば簡単にプログラムを作ることが可能です。
もし手軽に管理用スクリプトを作る機会があれば、ぜひRubyの外部コマンドを実行する機能を活用してください。
Open3.popen3の使い道
コマンドによってはターミナルなどから入力を受けて、その結果をターミナルに表示するものがあります。このターミナルへの入力が標準入力、そしてターミナルへの表示が標準出力と言います。Open3.popen3は、そのような外部コマンドの標準入力に文字列を送り、そのコマンドの標準出力を受け取る機能をRubyで作る場合に使います。