Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

【Ruby入門】外部コマンドを実行する4つの方法!system・%x・fork+exec・popenの使い分けを徹底解説

Rubyプログラムから外部コマンドを実行したい場面はよくあります。例えば、HTMLファイルをPDFに変換できるwkhtmltopdfのようなツールを利用したいケースなどが典型です。

Rubyには外部コマンドを実行するためのメソッドがいくつか用意されていますが、どのメソッドを選ぶかによって挙動や結果が大きく異なります

この記事では、それぞれの方法の特徴と使い方を詳しく解説していきます。

systemメソッド ― 最もシンプルな実行方法

systemメソッドは、Rubyから外部コマンドを実行する最もシンプルな方法です。

基本的な使い方はこちら

system("ls")

systemメソッドには、主に2つの特徴があります。

  • コマンドの出力は、実行時にそのままコンソールへ表示される
  • コマンドが完了するまで、Rubyプログラムの処理がブロックされる(待機する)

実際に試してみましょう。

system("sleep 2")

このコードを実行すると、2秒間処理が止まることが確認できます。バックグラウンドでコマンドを実行する方法については、記事の後半で紹介します。

戻り値の種類

systemメソッドは、3種類の戻り値を返します。

  • true:コマンドが正常に実行された場合
  • false:コマンドがエラーコードを返した場合
  • nil:コマンドの実行自体に失敗した場合(コマンドが見つからないなど)

さらに、直前に実行した外部コマンドの終了ステータス(終了コード)は、グローバル変数$?で取得できます。このステータスコードを確認することで、コマンドが失敗した原因をより詳しく把握できるでしょう。

シェル展開(Shell Expansion)とは?

systemメソッドで外部コマンドを実行すると、「シェル展開」の効果が適用されます。

シェル展開とは、シェル(sh/bash/zsh)がコマンド内の特殊文字(*?[ など)を受け取り、それらをファイル名のリストへ展開して置き換える仕組みのことです。

具体例を見てみましょう。

system("echo *")

このコードは、カレントディレクトリ内のすべてのファイルとフォルダを出力します。*は、コマンドが実行される前の段階でファイルリストに置き換えられるのです。

もし特殊文字をそのままの文字列として扱いたい場合は、引数をsystemメソッドの第2引数として渡します。

system("echo", "*")

この場合、出力結果は * そのものになります。

環境変数を指定して実行する方法

外部コマンドに特定の環境変数を渡したい場合は、ハッシュを第1引数として指定できます。

以下がその例です。

system({"rubyguides" => "best"}, "ruby", "-e p ENV['rubyguides']")

# "best"

この方法なら、Rubyアプリケーション自身の環境変数は変更されず、実行するコマンドに対してのみ環境変数が適用されます。

%x / Kernel#`(バッククォート)― 出力を文字列として取得

コマンドの出力を画面に表示するのではなく、文字列として受け取りたい場合は、%x記法またはKernel#`メソッド(バッククォート)を使用します。両者はまったく同じ動作をします。

まずはバッククォートの例

`ls`

続いて、%x記法の例:

%x|ls|

これらの例では、lsコマンドの出力結果が文字列として返却されます。

なお、スレッド内で実行しない限り、コマンドが完了するまで待機が必要になる点はsystemメソッドと同様です。

fork + exec で別プロセスとして実行する

forkは現在のプロセス(Rubyアプリ)のコピーを作成するメソッドで、execはそのコピーを別のプロセスへ置き換えるメソッドです。

注意forkメソッドはWindows環境では利用できません。

これはUnix系OSの世界で広く使われている定番パターンです。

動作イメージはこちら

fork { exec("ls") }

このコードは、別プロセス上でlsコマンドを実行し、その出力を表示します。

コマンドが独立したプロセスで実行されるため、systemメソッドや%xのようにRubyアプリ本体の処理をブロックすることがありません。

重要なポイント

forkなしでexecだけを使うと、現在のプロセス自体が置き換えられます。つまり、Rubyプログラムはその時点で終了してしまうので、十分注意してください。

IO.popen で双方向通信を行う

以下のようなニーズがある場合:

  • プロセスをより細かく制御したい
  • 外部プログラムとの双方向通信が必要

そのようなときは、IO.popenメソッドが最適な選択肢となります。

次の例では、popenメソッドでirbプロセスを起動し、入力を送信した後に出力を読み取っています。

サンプルコード

r = IO.popen("irb", "r+")

r.write "puts 123 + 1\n"

3.times { puts r.gets }

r.write "exit\n"

変数rはIOオブジェクトなので、通常のファイルと同じように読み書きが可能です。

popenを使う場合も、外部コマンドは独立したプロセスで実行されるため、わざわざスレッドを立てる必要はありません。

また、標準ライブラリにはpopen3メソッドも用意されています。通常のpopenとの違いは、標準出力とエラーメッセージを別々のIOオブジェクトに分割して扱える点です。

まとめ:目的に応じて最適なメソッドを選ぼう

この記事では、Rubyから外部コマンドを操作するさまざまな方法を学びました。最後に、それぞれの特徴を整理しておきます。

メソッド主な特徴
system出力はそのまま表示され、戻り値で成否を判定できる
%x / バッククォートコマンドの出力を文字列として取得できる
fork + exec別プロセスで実行でき、アプリをブロックしない
IO.popen双方向通信や細かなプロセス制御が可能

これらの機能を使う際は、セキュリティ面に十分注意してください。ユーザーからの入力をそのままコマンドに渡すと、深刻なセキュリティ問題につながる可能性があります。必ず入力値の検証やサニタイズを行いましょう。

この記事が役に立ったら、ぜひシェアして更多人に届けてください。

最後までお読みいただきありがとうございました 🙂

  1. Windows 10からトロイの木馬を検出・削除する方法【完全ガイド】

    インターネットのない生活はもはや想像できません。ハッカーはこの現実につけ込み、トロイの木馬やウイルスといった脅威をネット経由で拡散しています。これらのマルウェアはシステムに侵入するだけでなく、PCを乗っ取って金銭を奪おうとします。だからこそ、適切な対策を講じ、PCへの感染を未然に防ぐことが重要です。 ウイルス・トロイの木馬・マルウェアを最も簡単に検出・削除する方法 「マルウェア」とは、ランサムウェア、ワーム、アドウェア、トロイの木馬などを総称する言葉です。PCやスマートフォンに感染しようとする悪意のあるソフトウェアであり、これらの脅威からシステムを守る最も手軽な方法は、優れたアンチウイルスソ

  2. コマンドプロンプトとPowerShellでアプリをインストールする方法|Chocolatey完全ガイド

    ソフトウェアのインストールは、手間がかかり、繰り返し作業になりやすく、ミスも起こりやすいプロセスです。アプリを使い始めるまでに、ダウンロード→インストーラーの起動→完了待ちという流れが必要で、多くの時間を消費します。コマンドプロンプトからのアプリインストール方法を覚えれば、この時間を大幅に節約できます。さらにPowerShellを使えば、複数のアプリを同時にインストールすることも可能です。 PowerShellとコマンドプロンプトは、Windows 10/11上のアプリケーションをスムーズにインストールできるツールです。ただし、それぞれインストール手順には若干の違いがあります。本ガイドでは、コ