Как выполнять команды Unix через Windows / Cygwin с использованием Java - PullRequest
10 голосов
/ 19 июля 2011

Я пытаюсь выполнить две вещи:

  1. Я запускаю cygwin в Windows7 для выполнения команд оболочки Unix, и мне нужно автоматизировать процесс, написав приложение на Java.Я уже знаю, как использовать оболочку Windows через Java, используя «Класс процесса» и Runtime.getRuntime().exec("cmd /c dir").Я должен быть в состоянии сделать то же самое с командами Unix: то есть: ls -la и так далее.На что мне обратить внимание?

  2. Есть ли способ запомнить состояние оболочки?объяснение: когда я использую: Runtime.getRuntime().exec("cmd /c dir"), я всегда получаю список моего домашнего каталога.Если я сделаю Runtime.getRuntime().exec("cmd /c cd <some-folder>"), а затем еще раз Runtime.getRuntime().exec("cmd /c dir"), я все равно получу список моей домашней папки.Есть ли способ сообщить процессу, что он запомнил его состояние, как обычная оболочка?


Кажется, что предложенная Paŭlo командная строка bash не работает:

C:\cygwin\bin>bash -c ls -la
-la: ls: command not found

У меня проблемы с выяснением технических деталей.

Это мой код:

p = Runtime.getRuntime().exec("C:\\cygwin\\bin\\bash.exe -c ls -la");
reader2 = new BufferedReader(new InputStreamReader(p.getInputStream()));
line = reader2.readLine();

line в конечном итоге имеет нулевое значение.


Я добавил это в свой .bash_profile:

#BASH
export BASH_HOME=/cygdrive/c/cygwin
export PATH=$BASH_HOME/bin:$PATH

Я также добавил следующее:

Свойства системы -> Дополнительно -> Переменные среды -> user variebales -> переменная: BASH, значение: c:\cygwin\bin

Все равно ничего ...

Однако, если я выполню это вместо этого, оно будет работать!

p = Runtime.getRuntime().exec("c:\\cygwin\\bin\\ls -la ~/\"Eclipse_Workspace/RenameScript/files copy\"");

Ответы [ 2 ]

11 голосов
/ 19 июля 2011

1.Вызов команд Unix:

Вам просто нужно вызвать оболочку Unix (например, bash, поставляемую с Cygwin) вместо cmd.

bash -c "ls -la"

.Конечно, если ваша команда является внешней программой, вы можете просто вызвать ее напрямую:

ls -la

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

Process p = 
     Runtime.getRuntime().exec(new String[]{"C:\\cygwin\\bin\\bash.exe",
                                            "-c", "ls -la"},
                               new String[]{"PATH=/cygdrive/c/cygwin/bin"});

Сообщение об ошибке в вашем примере (ls: command not found), кажется, показывает, что ваш bash не может найти lsкоманда.Возможно, вам нужно поместить его в переменную PATH (см. Выше, как это сделать из Java).

Возможно, вместо /cygdrive/c/cygwin/bin, правильное имя каталога будет /usr/bin.

(Здесь все немного сложнее из-за необходимости везде соединять соглашения Unix и Windows.)

Простую команду ls можно назвать так:

Process p = Runtime.getRuntime().exec(new String[]{"C:\\cygwin\\bin\\ls.exe", "-la"});

2.Вызов нескольких команд:

Существует два основных способа вызова нескольких команд в одной оболочке:

  • , передавая их все сразу в оболочку;или
  • , передавая их интерактивно в оболочку.

Для первого способа просто введите несколько команд в качестве аргумента опции -c, разделенных ; или \n(перевод строки), например:

bash -c "cd /bin/ ; ls -la"

или из Java (адаптируя приведенный выше пример):

Process p = 
     Runtime.getRuntime().exec(new String[]{"C:\\cygwin\\bin\\bash.exe",
                                            "-c", "cd /bin/; ls -la"},
                               new String[]{"PATH=/cygdrive/c/cygwin/bin"});

Здесь оболочка будет анализировать командную строку как и выполнять ее каксценарий.Если он содержит несколько команд, все они будут выполнены, если по какой-либо причине оболочка не завершит работу (например, команда exit).(Я не уверен, что Windows cmd работает аналогичным образом. Пожалуйста, протестируйте и сообщите.)

Вместо передачи команд bash (или cmd или любой другой оболочки, которую вы используете) командамВ командной строке вы можете передать их через поток ввода Process.

  • Оболочка, запущенная в «режиме ввода» (например, та, которая не получила ни опции -c, ни аргумента файла сценария оболочки), будетчитать ввод из потока и интерпретировать первую строку как команду (или несколько).
  • Затем она выполнит эту команду.Сама команда может прочитать больше входных данных из потока, если она этого захочет.
  • Затем оболочка прочитает следующую строку, интерпретирует ее как команду и выполнит.
  • (В некоторых случаяхshell должен читать более одной строки, например, для длинных строк или составных команд, таких как циклы if или.)
  • Это будет продолжаться до конца потока (например, stream.close () на вашей стороне).) или выполнение явной команды exit (или некоторые другие причины для выхода).

Вот пример для этого:

Process p = Runtime.getRuntime().exec(new String[]{"C:\\cygwin\\bin\\bash.exe", "-s"});
InputStream outStream = p.getInputStream(); // normal output of the shell
InputStream errStream = p.getInputStream(); // error output of the shell
// TODO: start separate threads to read these streams

PrintStream ps = new PrintStream(p.getOutputStream());
ps.println("cd /bin/");
ps.println("ls -la");
ps.println("exit");
ps.close();
1 голос
/ 19 июля 2011

Вам не нужен Cygwin здесь.Есть несколько чистых библиотек Java, реализующих протокол SSH.Используй их.Кстати, они решат вашу вторую проблему.Вы откроете сеанс и выполните команду в том же сеансе, поэтому состояние оболочки будет сохранено автоматически.

Одним из примеров будет JSch .

...