web-dev-qa-db-ja.com

ProcessBuilderの環境を設定する

Linux環境をJava(1.6);具体的には "PATH"変数から設定するという奇妙な問題があります。

一言で言えば、私はJava.lang.ProcessBuilderを使用するネイティブプロセスを実行するためのパイプラインを持っています。ユーザーはオプションで、HashMapという名前のenvironmentを介して環境変数を設定できます。

ProcessBuilder pb = new ProcessBuilder(args);
Map<String, String> env = pb.environment();
if (environment != null)
   env.putAll(environment);
Process process = pb.start();

env変数は、コンソールにダンプすると、PATH変数の正しい値で正しく設定されます。ただし、プロセスを実行すると、Exceptionがスローされます。

Java.io.IOException: error=2, No such file or directory

同じプロセスは、ターミナルシェルの同じ環境変数で正常に実行されます。これをテストするために、ターミナルで環境を設定した後にEclipseを実行しました。この場合、ProcessBuilderプロセスは正しく実行されます。

したがって、何が起こっているのかというと、ProcessBuilderは私が設定した環境ではなく、現在のシステム環境を使用しているということです。

この問題に対する満足のいく答えをオンラインで見つけることができません。おそらくこれはOS固有の問題ですか?または私が欠けている何か他のもの?

11
Andrew Reid

バグではないと思います。環境変数の境界と役割を理解することは問題だと思います。 ProcessBuilder.environment()には、生成されたプロセスに対して「プロセスローカル」になる環境変数が含まれています。これらはシステム全体またはログオン全体ではなく、ProcessBuilderが実行されている環境にも影響しません。

ProcessBuilder.environment()マップには、生成されたプロセスによって表示されるプロセスローカル変数が含まれていますのみ。明らかに、ProcessBuilder.environment()を確認することで生成された処理の前提条件は、プロセスの生成が成功することです。これは、あなたが到達しているとは思えない点です。

私の知る限り、現在実行中のプロセスのPATHを(Javaから)変更することは実際には不可能です。これは、あなたが期待している(または実行できる)と思います。したがって、指摘する必要があると思います。起動しようとしている実行可能ファイルへの完全修飾パスへのProcessBuilder(または、ProcessBuilderを使用するJVMを起動する前に、PATHが正しく設定されていることを確認してください。これは、の「作業」シナリオで行ったことです。 IDEを起動する前にターミナルで設定してください)。

13
Mike Clark

Linuxの場合:

String path = System.getenv("HOME");

ProcessBuilder pb = new ProcessBuilder("/bin/bash","-c","export PATH=" +
    "PATH-TO-ADD" + ":" + path + " && exec");

この場合、PATH変数は必要に応じて更新され、実行可能ファイルは新しい$PATHで検索されます。これはLinuxでうまくいきました。

7
Sandeep

環境変数はプロセスコンテキストに対してローカルであることを理解する必要があります。新しいプロセスは親の環境のコピーを取得しますが、各コピーは独立しています。親の変更は既存の子(新しい子のみ)には影響せず、子の変更はparentの親または新しい子には影響しません。

あなたの場合、Javaプロセスは子プロセスを作成し、変更されたPATH変数を子のコンテキストに配置します。これはJava =プロセス。子プロセスはシェルではないため、PATH変数を無視します。プロセスはOSサービスを使用して直接作成されます。これらは、Javaのコンテキストを調べます。シェルで環境を変更しない限り、古いPATH変数を含むプロセスbefore Javaプロセスを開始します。

問題を解決するには、2つの選択肢があります。

  1. JavaでPATH変数を調べ、それをパス要素に分割して、実行可能ファイルを手動で検索します。次に、絶対パスを使用してProcessBuilderを呼び出すことができますand新しいPATHを子に配置して、孫が正しいパスを持つようにします。

  2. シェルを呼び出して、子プロセスを開始します。シェルはそのパス(環境を介して渡すことができます)を使用します。

2番目のケースは次のように機能します。

  1. 正しいPATHを使用して環境を作成します。
  2. シェルプロセスを開始します。
  3. シェルに引数として実行するコマンドを渡します("sh", "-c", "cmd args"または"cmd.exe", "/c", "cmd args"
  4. シェルは、コマンドを実行する必要があることに気付くでしょう
  5. 環境(手順1で構成したもの)を調べ、変更されたPATHを見つけて、正しいコマンドを実行します。

2番目のケースの欠点は、コマンド(args)の引数を適切にエスケープまたは引用符で囲む必要があることです。そうしないと、スペースやその他の特殊文字によって問題が発生します。

6
Aaron Digulla

ProcessBuilder javadocから明らかなことの1つは、environment()メソッドを使用して環境変数を取得し、次にmodify返されたマップを取得できることです。そのProcessBuilderインスタンスから起動された後続プロセスに変更が加えられます。

1
David

これは、Javaおよび外部プロセスの実際の問題のようです。

windows7およびJava 7(32ビット)

ProcessBuilder b = new ProcessBuilder();
Map<String, String> env = b.environment();
for (String key : env.keySet())
     System.out.println(key + ": " + env.get(key));

を生成します

SystemRoot: C:\Windows
Path: xbox

これは、実行中のプログラム環境とサブプロセス環境に、正確に値 'xbox'を持つパス変数が含まれている必要があることを意味します(たとえば、ナンセンス、私のPCのどこにもxboxという名前のディレクトリはありません)

プロトコルのためだけに:

Map<String, String> env = System.getenv();
    for (String key : env.keySet())
        System.out.println(key + ": " + env.get(key));

まったく同じ結果が得られます。

私が走るとき

b.command("convert.exe", "/?").inheritIO().start();

このプロセスビルダーと環境で私は得ます

    Konvertiert FAT-Volumes in NTFS.

CONVERT Volume /FS:NTFS [/V] [/CvtArea:Dateiname] [/NoSecurity] [/X]

  Volume      Bestimmt den Laufwerkbuchstaben (gefolgt von einem Doppelpunkt),
              den Bereitstellungspunkt oder das Volume.
  /FS:NTFS    Bestimmt das in NTFS zu konvertierende Volume.
  /V          Legt fest, dass CONVERT im ausf�hrlichen Modus ausgef�hrt wird.
  /CvtArea:Dateiname
              Bestimmt die zusammenh�ngende Datei im Stammverzeichnis, die als
              Platzhalter f�r NTFS-Systemdateien dienen soll.
  /NoSecurity Bestimmt die Sicherheitseinstellungen f�r konvertierte Dateien
              und Verzeichnisse, die f�r jeden Benutzer zug�nglich sind.
  /X          Erzwingt ggf. das Aufheben der Bereitstellung.
              Alle ge�ffneten Handles auf das Volume sind in diesem Fall 
              ung�ltig.

これはの(ドイツ語)出力です

C:\Windows\System32\convert.exe

私が使用するときも同じことが起こります

Runtime.getRuntime().exec(new String[]{"convert.exe", "/?"});

また、ネイティブ環境を置き換えたため、私の環境は非常に小さいことに注意してください。つまり、プログラム全体にこれら2つの環境変数が正確に含まれています。

0
John Smith

私はあなたが正しいと思います。現在実行中のJavaコードは、実行中の子プロセス用に準備している環境変数を使用しません。変数を渡して実行させることができる中間実行可能ファイルまたはスクリプトを作成できます。プログラム。

0
Sarel Botha