ProcessBuilder
JavaにおけるProcessBuilderとは、外部コマンド(ざっくり言えばコマンドプロンプトで使えるコマンドすべて)をJavaから実行するためのパイプ。(超おおざっぱ)
書き方
ProcessBuilder pb = new ProcessBuilder(ここに外部コマンドを入れる);
Process p;
try{
p = pb.start();
p.wairFor(); // 外部コマンドの実行が終わるまで待つ
}catch(IOException e){
e.printStackTrace();
}
注意点 兼 メインテーマ
ProcessBuilderのインスタンスを生成する際には引数を渡さなくてはならない。
シェルで実行可能なコマンドなら何でも渡せる(ハズ)。
そしてこのコマンド(引数)の渡し方に注意しなくてはならない。
コンストラクタは文字列とリスト(String)の両方を受け取ることが出来るとしているが、
(出典:https://docs.oracle.com/javase/jp/8/docs/api/java/lang/ProcessBuilder.html)
まあ、割と嘘である。
(ここからの動作例はUbuntu 20.04LTS におけるものです。)
ただの文字列だとプロセスに正しく受け取ってもらえないことがある。
例えば
ProcessBuilder pb = new ProcessBuilder("wget google.com");
のような書き方をしてみる。
そして実行すると
エラー:そのようなファイルやディレクトリは存在しません
と言われる。
本来ならGoogleのindex.htmlを取ってきてくれるはずなのだがエラーを吐く。
次にリストを引数にとってみる。
ProcessBuilder pb = new ProcessBuilder("wget","google.com");
すると…
google.com (google.com) をDNSに問いあわせています...
と出力され、この下にもずらずらと情報が出てきて、最終的にindex.html
を取得することが出来る。
文字列じゃいかんのか!
どうしてリストじゃないとダメなの?
調査中
よーくコンストラクタの説明文を見比べてみると、文字列の方は「プロセス・ビルダーのコマンドを同じ順序で設定する簡易コンストラクタです。」と書いてある。
文字列からリストを作成してプロセスに渡しているらしいが、ここがうまくいっていないのだろう。(多分)
終わりに
まさかここじゃないだろうなと思いこんだまま他の箇所に原因を見出そうとしていたので2時間ほど悩まされました。
思い込みは危険じゃ危険じゃ