Arhn - архитектура программирования

Использование команды Java exec, когда вы не знаете, есть ли пробелы

Я борюсь с ошибкой пробелов в методе exec Java Runtime. Вот что уникально в этой проблеме: команда, которую я пытаюсь выполнить, представляет собой входящую строку, может содержать или не содержать пробелы и не обязательно в каком-либо конкретном формате. В любом случае, мне нужно его выполнить. Если нет пробелов, я в порядке; если есть пробелы, я не так хорош.

Как объяснить оба обстоятельства?

Бонусная информация без дополнительной оплаты: кажется, что одна из больших проблем заключается в том, что я пытаюсь вызвать исполняемый файл в c:\program files\blablabla... и кажется, что exec разделяется на пробел после 'c:\program' . Я уверен, что с параметрами возникнут и другие проблемы.

Вот более конкретный пример строк, которые я могу получить. Это должно прояснить некоторую путаницу:

  • c:\someApp\someapp.exe
  • c:\someApp\someapp.exe -someParam=foo
  • c:\program files\someapp\someapp.exe
  • c:\program files\someapp\someapp.exe -someParam=bar

Первый работает нормально, потому что в нем нет пробелов. Со вторым даже все в порядке, потому что оно разбивается на пространство и использует первое как команду, а второе как параметр. В третьем и четвертом примерах, разделенных первым пробелом, в качестве параметров используются «C:\program» и команда «files...» и (в случае четвертой строки) «-someParam=bar».


  • Можете ли вы выполнить предварительную обработку входящей строки? Если это так, вы можете использовать метод Runtime.exec(String[] cmdarray), который будет обрабатывать пробелы за вас, предполагая, что вы можете разбить входящую строку на аргументы. 01.11.2010
  • Мусор на входе, мусор на выходе; вы не можете разобрать бессмысленную строку. Убедитесь, что отправитель избегает пробелов, которые вы хотите сохранить, или заключайте строки, которые идут вместе, в кавычки; только таким образом ваша проблема превращается из невозможной в довольно сложную. 01.11.2010

Ответы:


1

На самом деле я сделаю это ответом, а не комментарием: (из J2SE 1.5, Runtime.exec(String[]))

Предполагая, что вы можете выполнить предварительную обработку, используйте массив String, чтобы облегчить проблемы с пробелами в командах, должно работать следующее:

String[] args = {"C:\Program Files\app\app.exe","C:\Data Files\data1.dat"};
Runtime.exec(args);

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

ИЗМЕНИТЬ

Это сработает, если пробелы появятся в пути к исполняемому файлу, но не поможет вам с пробелами в аргументах.

String input = "c:\\program files\\someapp\\someapp.exe -someParam=bar";
int firstSplit = input.indexOf(".exe") + 4; //account for length of ".exe"
String command = input.substring(0,firstSplit);
String args = input.substring(firstSplit).trim(); //trim off extraneous whitespace
String[] argarray = args.split(" ");
String[] cmdargs = new String[argarray.length + 1];
cmdargs[0] = command;
for (int i = 0; i < argarray.length; i++) {
    cmdargs[i+1] = argarray[i];
}
Runtime.exec(cmdargs);

Обратите внимание, что это все еще довольно хрупко (и работает только для exe, а не для летучих мышей или чего-то еще). Если вам нужно учитывать пробелы в аргументах, вам потребуется выполнить дополнительную обработку либо строки args, либо строки argarray. Правильное решение состоит в том, чтобы ваши пользователи (или процесс ввода) правильно различали все аргументы.

01.11.2010
  • Я хотел бы сделать что-то подобное, но у меня нет надежного способа узнать, где сломать командную строку. 01.11.2010
  • Это делает вещи довольно неудачными, если не невозможными. Однако вы можете догадаться об этом: (из вашего редактирования), если пробелы встречаются только в пути к исполняемому файлу, предварительно обработайте все до .exe как одну команду, а затем выполните String.split() на оставшиеся варианты. Если сами параметры или аргументы могут содержать пробелы, это будет болезненно. Я отредактирую свой ответ, чтобы показать пример этого. 01.11.2010
  • for (int i = 0; i < argarray.length; i++) { cmdargs[i+1] = argarray[i]; } можно записать как System.arraycopy(argarray, 0, cmdargs, 1, argarray.length); 31.12.2010

  • 2

    Хорошо, у меня что-то работает, делая что-то вроде этого. Скажите, пожалуйста, есть ли проблема с этим подходом:

    
    try{
        String[] command = {"cmd", "/c", getMySuperAwesomeString()};
        Runtime.getRuntime().exec(command);
    }catch(IOExecption ioe){
        System.err.println("I'm borken");
    }
    
    

    В связи с этим следует ли вместо этого использовать ProcessBuilder?

    01.11.2010
  • Это, вероятно, сработает, в зависимости от процесса, который вы начинаете. Если он работает, он, вероятно, более гибкий, чем мой ответ (и с меньшим количеством кода). Вы просто перекладываете сложную часть определения аргументов на оболочку cmd :) Вам не нужен ProcessBuilder, если вы не хотите запускать целую кучу похожих процессов, поскольку вы столкнетесь с теми же проблемами токенизации. 01.11.2010
  • Да, в любом случае вы делаете предположения, верно? Спасибо за ваш вклад! 01.11.2010
  • Да, это то, что я должен был сделать в микросервисе, было настоящей головной болью, но этот метод кажется гораздо более надежным. 08.07.2016

  • 3

    Пример запуска файла JAR с пробелами в расположении файла:

    String qoutation = "\""
    String path = "C:\\JAR File\\File.jar"
    Runtime.getRuntime().exec("java -jar " + quotation + path + quotation);
    

    Это запускает команду: java -jar "C:\Jar File\File.jar"

    Когда в строке появляется обратная косая черта \, она используется как escape-последовательность, что фактически заставляет программу ее пропустить. Это позволяет нам использовать кавычки " в строке, а не начинать/закрывать строку.

    21.01.2013

    4

    Может быть, я слишком просто думаю, но может ли это работать?

    Runtime.exec(commandstring.split(" "));
    

    (Я предполагаю, что вы хотите, чтобы команда выполнялась так, как если бы она выполнялась в оболочке или около того.)

    01.11.2010
  • Я думаю, он думает о чем-то вроде command C:\Documents and Settings\user\datafile.dat, что вы не хотели бы интерпретировать как ["command","C:\Documents","and","Settings\user\datafile.dat"]. 01.11.2010

  • 5

    Я предполагаю, что вы можете предварительно обработать входящую строку. В этом случае вы можете увидеть, есть ли у вас ввод с пробелами:

    if("string with possible spaces".contains(" ")) {
        System.out.println("yay");
    }
    

    Обратите внимание, что это будет работать только в том случае, если во вводе есть фактический символ пробела. Если вы хотите быть более тщательным, предполагая, что символы табуляции или символы новой строки являются возможными входными данными, вы можете использовать регулярное выражение:

    String s = ".+\\s.+";
    Pattern p = Pattern.compile(s);
    
    Matcher m = p.matcher("string with possible spaces or    tabs");
    if(m.matches()) {
        System.out.println("yay");
    }
    

    Изменить: вы можете использовать предоставленный мной код, чтобы определить, есть ли пробелы во входных данных. Если их нет, то ничего делать не нужно. Если у вас есть пробелы, ситуация немного сложнее. Читая ответы других людей и ваш пересмотренный вопрос, я могу только предположить, что ввод с пробелами должен быть заключен в кавычки, поэтому пробел не испортит стандартное выполнение команды. В есть пробелы, вы должны:

    1. проверьте, есть ли какие-либо кавычки в вашем вводе
    2. если они есть, экранируйте их (измените " на \")
    3. окружить ввод кавычками (some input становится "some input")

    В конечном счете, вы хотите, чтобы ввод типа some "funky" input стал "some \"funky\" input".

    Примечание: остерегайтесь одинарных кавычек ('). Обращайтесь с ними соответствующим образом.

    01.11.2010
  • Я мог бы разделить его, но что мне делать с отдельными частями? Я просто не знаю, что у меня есть после того, как я разделил их. 01.11.2010

  • 6

    Я предполагаю, что это ошибка, с которой вы боретесь:

    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4506936

    http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=8582245ba20fa4da33ac0967e858?bug_id=4491217

    Они говорят, что обходной путь будет:

    Используйте JRE, которая не находится в пути, содержащем пробелы.

    Использование public Process exec(String[] cmdarray, String[] envp) вызывает IOException

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

    01.11.2010
  • Наша JRE не находится в пути, содержащем пробелы. 01.11.2010
  • О другой ошибке говорят, что вам нужно поместить все аргументы в отдельный слот: Подводя итог, единственный безопасный способ - поместить каждый аргумент в отдельный слот в массиве аргументов. Итак, используйте download.oracle.com/javase/1.4.2/docs/api/java/lang/ . Я исправлю исходный пост. 01.11.2010
  • Проблема в том, что я не знаю, что является аргументом, а что нет. 01.11.2010
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..