Java, Runtime.exec или ProcessBuilder: как узнать, является ли файл оболочкой или двоичным? - PullRequest
11 голосов
/ 09 января 2012

Я ищу наиболее эффективный способ решить:

  • Должен ли я предварительно представить пользовательскую командную строку с исполняемым файлом оболочки
  • Если да, каким будет этот исполняемый файл? (/ bin / sh? / usr / bin / perl? / usr / bin / ksh? c: /../ cmd.exe?)

Известно, что для запуска сценария оболочки из Java нужно вместо этого запустить оболочку:

ProcessBuilder pb = new ProcessBuilder("/bin/sh", "script.sh", "arg1", "arg2);

Чтобы запустить двоичный файл, нужно запустить сам двоичный файл:

ProcessBuilder pb = new ProcessBuilder("/path/binary", "arg1", "arg2);

Если двоичный файл выполняется с помощью оболочки, он выдает ошибку:

ProcessBuilder pb = new ProcessBuilder("/bin/sh", "/path/binary", "arg1", "arg2);
(sh: cannot execute binary file)

Если скрипт оболочки выполняется без двоичного файла оболочки, он выдает ошибку:

ProcessBuilder pb = new ProcessBuilder("script.sh", "arg1", "arg2);
(error 2: file not found)

Я нахожусь в ситуации, когда мое приложение не знает, что оно запускает, двоичный файл или сценарий.

Запущенное приложение является обработчиком событий, предоставляемым конечным пользователем . Скорее всего, это сценарий оболочки, выполняемый под Unix; но это может быть * .cmd под Windows или Perl-скрипт, выполняемый на какой-то непонятной платформе. В конце концов, это Java.

Моей первой наивной попыткой было запустить командную строку с оболочкой и посмотреть, работает ли она. Если нет, попробуйте выполнить его как двоичный файл.

Это уродливо и рискованно: при какой-то неизвестной комбинации платформы и оболочки второй прогон все еще может выполнить сценарий второй раз с непредсказуемыми результатами.

Кроме того, я не могу сказать, когда сценарий запускался нормально и не сработал из-за какой-то проблемы, с которой я просто не могу его запустить.

Лучшее, что я сейчас рассматриваю, это:

  • Прочитайте скрипт и поищите непечатаемые байты
  • Если найдено, считайте его двоичным
  • Если нет, добавьте / bin / sh (или cmd.exe, если под Windows)

Пожалуйста, сообщите, если у вас есть идеи получше.

ОБНОВЛЕНИЕ / ЧАСТИЧНОЕ РЕШЕНИЕ

Спасибо всем, кто поделился своими мыслями со мной.

Оказывается, я перепутал себя и остальную часть интернета:)

Не обязательно добавлять двоичный код перед введенной пользователем командной строкой, если:

  1. скрипт в PATH
  2. (для Unix) скрипт исполняемый
  3. (для Unix) скрипт имеет #! / Path / to / интерпретатор

Во время тестирования моего кода одно или другое из этих условий не выполнялось. : - (

После тщательного выполнения теста с нуля был выполнен скрипт.

Пункт 3 может быть выполнен только пользователем и должен быть задокументирован в Руководстве пользователя.

Из-за того, как эти сценарии распространяются на целевую систему, они могут не выполняться и могут отсутствовать в PATH.

Единственный путь, который мне небезразличен, является относительным, поэтому достаточно добавить ./ к любому относительному пути.

Создание сценариев, исполняемых под Unix (и любой другой платформой), является более сложной задачей. Это не WORA. Помещение / bin / sh перед ним может помочь, но, если я правильно помню, под Solaris оболочка не будет выполнять неисполняемый скрипт.

Я опубликую другое обновление позже на этой неделе.

Ответы [ 3 ]

3 голосов
/ 09 января 2012

Это должен быть красный флаг, который вы должны перепрыгивать через эти обручи только для запуска команды.Во-первых, потому что это становится действительно сложным, а во-вторых, потому что Java была разработана, чтобы быть независимой от платформы.Когда вы исследуете специфичные для ОС взломы, чтобы заставить работать встроенные классы, вы должны отступить и пересмотреть свои предположения.

ProcessBuilder pb = new ProcessBuilder("script.sh", "arg1", "arg2);
(error 2: file not found)

Обратите внимание, что сообщение об ошибке «файл не найден», а не «не может»выполнить сценарий оболочки "или некоторые такие ошибки.Наиболее вероятная причина этой ошибки не в том, что вы выполняете скрипт, а в том, что скрипт не может быть найден.

Если скрипт находится в текущем каталоге, вам нужно добавить ./спереди.Если вы не указали явный путь к исполняемому файлу, то исполняемый файл должен находиться в одном из каталогов в переменной среды $PATH.Текущий каталог . обычно не включен в $PATH по умолчанию.

ProcessBuilder pb = new ProcessBuilder("./script.sh", "arg1", "arg2);

Если имя сценария является предоставленным пользователем значением, то я бы наложил это требование напользователь - вы можете добавить ./ для них, но программы UNIX обычно стараются не быть слишком полезными.Если они забывают поставить ./, тогда это их проблема!

2 голосов
/ 09 января 2012

Одним из возможных решений является создание сценария, который оборачивает исполняемый сценарий / двоичный файл изнутри вашей программы. Таким образом, вы знаете, что это всегда сценарий. Сгенерированный скрипт просто выполняет внутренний скрипт / двоичный файл и возвращает код ошибки (и, возможно, перенаправляет ввод / вывод). Когда закончите, вы можете просто удалить его. Java позволяет очень легко создавать временные файлы.

0 голосов
/ 09 января 2012

Вкл.

ProcessBuilder pb = новый ProcessBuilder ("/ bin / sh", "/ path / binary", "arg1", "arg2); (sh: невозможно выполнить двоичный файл)

ProcessBuilder pb = new ProcessBuilder ("/ bin / sh", "-c", "/ path / binary", "arg1", "arg2);(sh: невозможно выполнить двоичный файл)

Один из вариантов - принять путь интерпретатора в качестве другого аргумента (возможно, из списка известных значений) от пользователей.

(Это могло бытькомментарий. Я не смог получить правильное форматирование)

...