14

Java (1.6) から Linux 環境を設定する際に奇妙な問題があります。特に「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();

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

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

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

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

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

4

6 に答える 6

16

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

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

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

于 2012-04-05T21:37:37.117 に答える
8

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

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

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

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

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

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

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

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

于 2015-12-03T08:34:05.057 に答える
8

Linux の場合:

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

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

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

于 2012-05-22T16:55:15.603 に答える
2

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

于 2012-11-30T01:53:31.923 に答える
0

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

Windows 7 および 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 つの環境変数を持っているということです。

于 2013-10-24T07:47:36.050 に答える
0

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

于 2012-04-05T21:18:18.390 に答える