Вопрос по java – Настройка среды для ProcessBuilder

9

У меня странная проблема с настройкой среды 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 использует не ту среду, которую я для нее установил, а текущую системную среду.

Я не могу найти удовлетворительных ответов на эту проблему в Интернете. Возможно, это проблема ОС? Или что-то еще, чего мне не хватает?

@PeterT Подсказка, которую вы дали, говоря, что Path на Windows была потрясающей !!! Я провел недели вместе из-за этой проблемы в ProcessBuilder !! БОЛЬШОЕ СПАСИБО !!! :) :) Destructor
Может быть, попытаться найти переменную PATH и опубликовать ее здесь, может быть, мы сможем что-то заметить .. barsju
@ Разрушитель рад помочь ... Я не могу вспомнить, как долго это меня срывало: не совсем недели, но достаточно долго, чтобы расстраиваться :) PeterT
Еще одна вещь, о которой следует знать в Windows, это то, что в случае имен переменных среды"typically not important" (процитироватьSystem.getenv Javadoc), так что вы можете позвонитьSystem.getenv("path") или жеSystem.getenv("PATH") взаимозаменяемо с аналогичными результатами, это не относится к полю среды ProcessBuilder, так какMap доступ напрямую, а не через определенный получатель, поэтому любое расхождение в заглавных букв приведет к ошибке ... Подсказка: если выdo хотите получить путь к ProcessBuilder в Windows, используйтеenvironment.get("Path"). PeterT

Ваш Ответ

6   ответов
7

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

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

В этом случаеPATH переменная обновляется в соответствии с необходимостью, и исполняемый файл ищется в новом$PATH, Это работало для меня в Linux.

Или запустите файл sh и отредактируйте его, чтобы получить переменные, которые вам нужны, прежде чем выполнять в этом скрипте sh
5

что переменные среды являются локальными для контекстов процесса. Новый процесс получает копию родительской среды, но каждая копия является независимой. Изменения в родителе не влияют на существующих детей (только на новых), а изменения в детях не влияют на родителей или новых детейparent.

В вашем случае процесс Java создает дочерний процесс и помещает измененныйPATH переменная в контексте ребенка. Это не влияет на процесс Java. Дочерний процесс не является оболочкой, поэтому он игнорируетPATH переменная. Процесс создается напрямую с использованием сервисов ОС. Те смотрят в контекст процесса Java, который содержит старыеPATH переменная, если вы не измените среду в оболочкеbefore Вы запускаете процесс Java.

Чтобы решить вашу проблему, у вас есть два варианта:

Examine the PATH variable in Java, split it into path elements and search for the executable manually. You can then invoke ProcessBuilder with the absolute path and put the new PATH into the child, so grandchildren will have the correct path.

Invoke a shell to start the child process. The shell will use it's path (which you can pass via the environment).

Второй случай работает так:

You create an environment with the correct PATH. You start a shell process. You pass the command to run as argument to the shell ("sh", "-c", "cmd args" or "cmd.exe", "/c", "cmd args") The shell will notice that it has to run a command It will look into it's environment (which you configured in step #1), find the modified PATH and run the correct command.

Недостаток второго случая заключается в том, что вы должны правильно экранировать и / или указывать аргументы для команды (args), или пробелы и другие специальные символы вызовут проблемы.

0

вы правы. В настоящий момент исполняемый код Java не будет использовать переменные среды, которые вы готовите для дочернего процесса, который вы выполняете. Вы можете создать промежуточный исполняемый файл или скрипт, в который вы можете передавать переменные, и он будет выполнять вашу программу.

13

что это ошибка, я думаю, что это проблема с вашим пониманием границ и ролей переменных среды в игре.ProcessBuilder.environment() содержит переменные среды, которые будут «локальными для процесса»; к порожденному процессу. Они не являются общесистемными или не входят в систему, и они даже не влияют на среду, в которой работает ProcessBuilder.

ProcessBuilder.environment() карта содержит локальные переменные процесса, которые будут видныonly порожденным процессом. Очевидно, что предпосылкой для порожденной обработки являетсяProcessBuilder.environment() это успешное порождение процесса, и я даже не думаю, что вы дошли до этого.

Насколько я знаю, на самом деле невозможно (из Java) изменить текущий запущенный процесс '. PATH, что, как я думаю, вы ожидаете (или можете сделать). Поэтому я думаю, что вы должны указать ProcessBuilder на полный путь к исполняемому файлу, который вы пытаетесь запустить (или быть уверенным, что PATH был правильно настроен еще до того, как вы запустили JVM, которая будет использовать ProcessBuilder, что вы и сделали в своем «рабочем» сценарии установки его в терминале перед запуском вашей IDE).

Спасибо, это очень полезно. Предполагая, что я указываю полный путь к целевому процессу, означает ли это, что он будет использоватьProcessBuilderпеременные среды процесса, если он выполняет свои собственные вызовы другим процессам? Это было бы подходящим решением для меня. Andrew Reid
Я не уверен, что полностью понимаю (особенно в том, что касается «вызовов других процессов»), но я уверен, что ответ «да».
Японял твою точку зрения. Можете ли вы указать мне документы, которые указывают то же самое?
1

что вы можете получить переменные среды с помощью метода environment (), а затемmodify возвращенная карта. любойsubsequent процесс, запущенный из этого экземпляра ProcessBuilder, будет иметь ваши изменения.

0

следующее на windows 7 и java 7 (32bit)

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

which means the running programs environment and the subprocesses environment should contain a path variable, that has exactly the value 'xbox' (например, ерунда, на моем компьютере нет каталога с именем 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", "/?"});

И обратите внимание, что моя среда настолько мала, потому что я заменил природную среду. Это означает, что вся программа имеет именно эти две переменные окружения.

Похожие вопросы