Ответ 1
Почему некоторые команды терпят неудачу?
Это происходит потому, что команда, переданная в Runtime.exec(String)
, не выполняется в оболочке. Оболочка выполняет множество общих служб поддержки для программ, и когда оболочка не собирается их выполнять, команда будет терпеть неудачу.
Когда команды не выполняются?
Команда будет терпеть неудачу всякий раз, когда это зависит от функций оболочки. В оболочке много общих, полезных вещей, о которых мы обычно не думаем:
-
Оболочка правильно раскладывается на кавычки и пробелы
Это гарантирует, что имя файла в
"My File.txt"
останется единственным аргументом.Runtime.exec(String)
наивно разбивается на пробелы и передает это как два отдельных имени файла. Это, очевидно, не удается. -
Оболочка расширяет globs/wildcards
При запуске
ls *.doc
оболочка перезаписывает его вls letter.doc notes.doc
.Runtime.exec(String)
нет, он просто передает их как аргументы.ls
не знает, что такое*
, поэтому команда не работает. -
Оболочка управляет каналами и перенаправлением.
При запуске
ls mydir > output.txt
оболочка открывает "output.txt" для вывода команды и удаляет ее из командной строки, предоставляяls mydir
.Runtime.exec(String)
нет. Он просто передает их в качестве аргументов.ls
не знает, что означает>
, поэтому команда не работает. -
Оболочка расширяет переменные и команды
При запуске
ls "$HOME"
илиls "$(pwd)"
оболочка перезаписывает его вls /home/myuser
.Runtime.exec(String)
нет, он просто передает их как аргументы.ls
не знает, что означает$
, поэтому команда не работает.
Что вы можете сделать вместо этого?
Существует два способа выполнения произвольно сложных команд:
Простой и неряшливый: делегировать оболочку.
Вы можете просто использовать Runtime.exec(String[])
(обратите внимание на параметр массива) и передать команду непосредственно в оболочку, которая может выполнять весь тяжелый подъем:
// Simple, sloppy fix. May have security and robustness implications
String myFile = "some filename.txt";
String myCommand = "cp -R '" + myFile + "' $HOME 2> errorlog";
Runtime.getRuntime().exec(new String[] { "bash", "-c", myCommand });
Безопасный и надежный: взять на себя обязанности оболочки.
Это не исправление, которое может быть применено механически, но требует понимания модели исполнения Unix, каких оболочек и как вы можете сделать то же самое. Тем не менее, вы можете получить надежное, надежное и надежное решение, сняв оболочку с рисунка. Этому способствует ProcessBuilder
.
Команда из предыдущего примера, которая требует, чтобы кто-то обрабатывал 1. кавычки, 2. переменные и 3. перенаправления, может быть записан как:
String myFile = "some filename.txt";
ProcessBuilder builder = new ProcessBuilder(
"cp", "-R", myFile, // We handle word splitting
System.getenv("HOME")); // We handle variables
builder.redirectError( // We set up redirections
ProcessBuilder.Redirect.to(new File("errorlog")));
builder.start();