タイトル鶴薗賢吾のCocoaはやっぱり!出張版》7. UNIXコマンドの実行(3)カテゴリーCocoa, 鶴薗賢吾のCocoaはやっぱり!出張版
作成日2002/1/22 1:57:50作成者新居雅行
では、細かく見ていきます。

// 実行準備
task = [ [ NSTask alloc ] init ]; // 生成と初期化
[ task setStandardOutput : [ NSPipe pipe ] ]; // 標準出力変更
[ task setStandardError : [ task standardOutput ] ]; // 標準エラー変更

まず、最初にNSTaskの生成と初期化をallocとinitで行います。

UNIXコマンドの多くは、実行結果を標準出力に出力します。そのため、何もしないと結果はコンソールに出力されてしまいます。このサンプルでは、テキストフィールドに出力していますので、コンソールに出力させずに、アプリケーション側で受け取る必要があります。NSTaskには、標準出力の出力先を変更する setStandardOutput : というメソッドがありますので、これを使います。

出力先には、ファイルハンドル ( NSFileHandle ) とパイプ ( NSPipe ) のどちらかが使用できます。ファイルハンドルを使用すると、指定のファイルへ書き出すことが出来ますし、パイプを使用するとパイプに出力内容がたまりますので、そこからファイルハンドルを使って読み出すことが出来ます。このサンプルでは、パイプに出力させて、そこから読み出してテキストフィールドに書き込んでいます。

標準エラーも同じく出力先をパイプにしておきます。メソッドはsetStandardError : を使います。

 ★ NSTask : コマンドの標準出力先を変更
  [書式] - (void) setStandardOutput : (id) file
  [入力] file : 出力先のファイル(NSFileHandle)かパイプ(NSPipe)を指定する。

 ★ NSTask : コマンドの標準出力先を取得
  [書式] - (id) standardOutput
  [出力] 返り値 : 設定されているファイル(NSFileHandle)かパイプ(NSPipe)
          のインスタンス。

 ★ NSTask : コマンドの標準エラーの出力先を変更
  [書式] - (void) setStandardError : (id) file
  [入力] file : ファイル(NSFileHandle)かパイプ(NSPipe)を指定する。

 ★ NSTask : コマンドの標準エラーの出力先を取得
  [書式] - (id) standardError
  [入力]
  [出力] 返り値 : 設定されているファイル(NSFileHandle)かパイプ(NSPipe)
          のインスタンス。

パイプを作るには、NSPipeのクラスメソッドであるpipeを実行するだけです。

 ★ NSPipe : パイプのインスタンスを生成
  [書式] + (id) pipe
  [出力] 返り値 : パイプのインスタンス。

続いて、実行するコマンドをsetLaunchPath : で設定し、コマンドに渡すパラメータをsetArguments : で設定します。

[ task setLaunchPath : [ arguments objectAtIndex : 0 ] ];
// コマンド設定
[ task setArguments : [ arguments subarrayWithRange :
NSMakeRange( 1, ([arguments count] - 1) ) ] ];
// パラメータ設定

 ★ NSTask : 起動するコマンドのパスを変更
  [書式] - (void) setLaunchPath : (NSString *) path
  [入力] path : 起動するコマンドのフルパスを指定する。

 ★ NSTask : 起動するコマンドのパスを取得
  [書式] - (NSString *) launchPath
  [出力] 返り値 : 起動するコマンドのフルパス。
 
 ★ NSTask : コマンドに渡すパラメータを変更
  [書式] - (void) setArguments : (NSArray *) arguments
  [入力] arguments : コマンドに渡すパラメータ。

 ★ NSTask : コマンドに渡すパラメータを取得
  [書式] - (NSArray *) arguments
  [出力] 返り値 : コマンドに渡すパラメータ。

このサンプルでは使用していませんが、カレントディレクトリを指定したり、取得したりするメソッドも用意されています。

 ★ NSTask : 実行時のカレントディレクトリを変更
  [書式] - (void) setCurrentDirectoryPath : (NSString *) path
  [入力] path : 実行時のカレントでディレクトリのフルパス。

 ★ NSTask : 実行時のカレントディレクトリを取得
  [書式] - (NSString *) currentDirectoryPath
  [出力] 返り値 : 実行時のカレントでディレクトリのフルパス。

通知設定のところは後回しにして、最後のlaunchメソッドを先に説明します。このlaunchメソッドを実行することで、UNIXコマンドが実行されます。UNIXコマンドは非同期で動きますので、このlaunchメソッドを呼んでもすぐに制御は戻ってきます。

[ task launch ]; // コマンド実行

 ★ NSTask : コマンドを実行
  [書式] - (void) launch
  [備考] コマンドは非同期に実行されるため、すぐに制御が戻ってくる。
  [出力] 返り値 :

◎ 通知を用いた実行結果の読み出し
先程、標準出力をパイプに変更しました。そして、パイプからの出力を読み出すのにはファイルハンドルを用いると説明しました。具体的には以下のようにしてファイルハンドルを得ることが出来ます。

NSFileHandle *fout = [ [ task standardOutput ] fileHandleForReading ] ];

standardOutputメソッドからパイプ ( NSPipe ) のインスタンスが返ってきますので、NSPipe読み込み用のファイルハンドルを取得するfileHandleForReadingを呼ぶことでファイルハンドルが得られます。

 ★ NSPipe : パイプから情報を読み出すためのファイルハンドルを取得
  [書式] - (NSFileHandle *) fileHandleForReading
  [出力] 返り値 : パイプから情報を読み出すためのファイルハンドルの
         インスタンス。availableData、readDataToEndOfFile、
         readDataOfLengthで読み出す。

 ★ NSPipe : パイプに情報を書き込むためのファイルハンドルを取得
  [書式] - (NSFileHandle *) fileHandleForWriting
  [出力] 返り値 : パイプに情報を書き込むためのファイルハンドルの
         インスタンス。writeDataで書き込む。

後は読み出し用のメソッドavailableDataなどを用いれば、読み出しが行えます。ただし、どういったタイミングで、パイプからデータが出力されてくるのかは、実行するUNIXコマンドに依存します。今回のlocateコマンドでは、瞬時にデータが出てきますが、インターネットから情報を取ってくるようなコマンドもあります。そのため、このサンプルでは、読み出しメソッドを呼ぶのではなくデータが得られた時にファイルハンドルに通知してもらうようなスタイルを採っています。
(この項続く)
[鶴薗賢吾]
関連リンクCocoaはやっぱり!