Сгенерировать команду linux с аргументами в Java

Я ищу библиотеку (Java/Scala), которая с учетом команды и списка аргументов создает String, которая при вставке в терминал bash выполнит данную команду со всеми ее аргументами (правильно экранированными).

Мне известен класс java.lang.ProcessBuilder. Это хорошо работает, если я хочу выполнить команду как подпроцесс. Вместо этого я ищу библиотеку, которая может генерировать строковое представление команды.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
127
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Обычно я бы не советовал людям пытаться писать свои собственные эскейперы, но в этом случае это не страшно, потому что строки в одинарных кавычках bash будут правильно заключать каждый отдельный символ, кроме байтов NUL и вложенных одинарных кавычек:

  public static String bashEscape(String[] arguments) {
    StringBuilder sb = new StringBuilder();
    for(String arg : arguments) {
      if (arg.indexOf(0) != -1) {
        throw new IllegalArgumentException("Shell arguments can't represent NUL bytes");
      }
      sb.append("'").append(arg.replaceAll("'", "'\\\\''")).append("' ");
    }
    return sb.toString();
  }

Это правильно убегает:

  • Все типы кавычек, включая одинарные, двойные кавычки, обратные кавычки и обратную косую черту.
  • Все формы метасимволов оболочки, например *?![]()|<>&;$ и пробелы.
  • Все обычные буквенно-цифровые символы, очевидно
  • Перевод строки, возврат и другие управляющие символы

Единственное, о чем нужно помнить, это то, что вы и ваша оболочка должны согласовать кодировку символов, когда вы передаете ей строку.

Небольшим улучшением было бы использование String#replace вместо String#replaceAll, так как в этом случае нам не нужно сопоставление регулярных выражений.

SlavaSt 20.10.2021 02:53

Вы можете распечатать команду, которую собирается запустить ProcessBuilder, а затем не запускать ее. «cmd» будет любой командой, которую ваше приложение генерирует на основе аргументов.

ProcessBuilder processBuilder = new ProcessBuilder(cmd);
String command = processBuilder.command().toString();

Я попробовал это с cmd = "ls", что заставило command содержать [ls]. Когда я копирую это в свою оболочку, я получаю bash: [ls]: command not found. Если я ввожу ls напрямую, файлы отображаются как обычно. У вас другой результат?

that other guy 01.03.2019 00:36

Ах да, processBuilder.command() возвращает List<String>, так что вам потребуется либо String.join("", processBuilder.command()), который даст вам команду, либо итерацию по списку, добавляя каждый элемент в String, и это сработает. Я предполагаю, что у вас действительно будет только один элемент в списке, поэтому String.join("", processBuilder.command()) будет легко и просто.

tmace 01.03.2019 01:05

Обычно у вас есть несколько элементов, например. new ProcessBuilder("ls", "-l", "My File.txt"); Если вы присоединитесь к "", вы получите ls-lMy File.txt, что приведет к ls-lMy: command not found. Если вы присоединитесь к пробелам, вы получите ls -l My File.txt, что приведет к ls: cannot access 'My': No such file or directory. Эквивалентная команда bash в этом случае должна быть, например. ls -l "My File.txt" чтобы сохранить пробел в последнем аргументе

that other guy 01.03.2019 18:04

Возможно, вам было бы полезнее опубликовать свой код, чтобы я мог точно ответить на примере, который соответствует вашим потребностям. Я понимаю, что processbuilder принимает несколько параметров. Вы действительно заполняете его несколькими параметрами? У вас есть пример того, как вы это делаете? Если их можно соединить пробелами, то разве это не решит проблему? Ваша команда будет выполнена успешно, если вы присоединяетесь с помощью пробелов, и приведенный выше пример ProcessBuilder действительно является тем, что вы используете в своем коде.

tmace 01.03.2019 18:07

Я не ОП, но нет, в моем примере объединение пробелов не работает, потому что это не учитывает пробелы в одном аргументе. Вы можете быть уверены, что OP будет использовать несколько параметров, потому что они спрашивают о «команде и списке аргументов», а ProcessBuilder не поддерживает аргументы без нескольких параметров (например, вы не можете использовать new ProcessBuilder("ls -l 'My File.txt'"), потому что ProcessBuilder не вызывает оболочку).

that other guy 01.03.2019 18:22

Другие вопросы по теме