Как выполнять команды cmd через Java

Я пытаюсь выполнить аргументы командной строки через Java. Например:

// Execute command
String command = "cmd /c start cmd.exe";
Process child = Runtime.getRuntime().exec(command);

// Get output stream to write from it
OutputStream out = child.getOutputStream();

out.write("cd C:/ /r/n".getBytes());
out.flush();
out.write("dir /r/n".getBytes());
out.close();

Приведенное выше открывает командную строку, но не выполняет cd или dir. Есть идеи? Я использую Windows XP, JRE6.

(Я пересмотрел свой вопрос, чтобы сделать его более конкретным. Следующие ответы были полезны, но не отвечают на мой вопрос.)


person joe    schedule 11.11.2010    source источник
comment
Джо, если вы все еще чувствуете, что на ваш вопрос не ответили, я думаю, вам следует предоставить больше информации. Мой ответ определенно делает то, чего вы хотите достичь, а именно перечисляет файлы в C:\. Ответы Винсента и Карлеса показывают, как запускать несколько команд оболочки из одного вызова exec(). Я не уверен, что вас не устраивает на данный момент.   -  person Andrzej Doyle    schedule 12.11.2010


Ответы (11)


Код, который вы разместили, запускает три разных процесса, каждый из которых имеет свою собственную команду. Чтобы открыть командную строку, а затем запустить команду, попробуйте следующее (сам никогда не пробовал):

try {
    // Execute command
    String command = "cmd /c start cmd.exe";
    Process child = Runtime.getRuntime().exec(command);

    // Get output stream to write from it
    OutputStream out = child.getOutputStream();

    out.write("cd C:/ /r/n".getBytes());
    out.flush();
    out.write("dir /r/n".getBytes());
    out.close();
} catch (IOException e) {
}
person Peter Knego    schedule 11.11.2010
comment
Спасибо. Это открывает командную строку, но не выполняет команду cd или dir. - person joe; 11.11.2010
comment
Ну и дела, я люблю фрагменты кода с отказом от ответственности: никогда не пробовал это сам. ›_‹ - person b1nary.atr0phy; 28.08.2012
comment
Это открывает командную строку, но не выполняет команду cd или dir, почему? - person Akhilesh Dhar Dubey; 21.04.2013
comment
почему он был одобрен ... его ложноположительный результат! - person Sejwal; 14.08.2013
comment
Я думаю, по крайней мере, /n следует изменить на \n. Но в целом выполняемая команда и способ управления оболочкой весьма сомнительны. - person eckes; 05.10.2014
comment
Ответы ниже имеют фактический ответ. - person Mgamerz; 26.10.2014

Я нашел это на forums.oracle.com

Позволяет повторно использовать процесс для выполнения нескольких команд в Windows: http://kr.forums.oracle.com/forums/thread.jspa?messageID=9250051

Вам нужно что-то вроде

   String[] command =
    {
        "cmd",
    };
    Process p = Runtime.getRuntime().exec(command);
    new Thread(new SyncPipe(p.getErrorStream(), System.err)).start();
    new Thread(new SyncPipe(p.getInputStream(), System.out)).start();
    PrintWriter stdin = new PrintWriter(p.getOutputStream());
    stdin.println("dir c:\\ /A /Q");
    // write any other commands you want here
    stdin.close();
    int returnCode = p.waitFor();
    System.out.println("Return code = " + returnCode);

Класс SyncPipe:

class SyncPipe implements Runnable
{
public SyncPipe(InputStream istrm, OutputStream ostrm) {
      istrm_ = istrm;
      ostrm_ = ostrm;
  }
  public void run() {
      try
      {
          final byte[] buffer = new byte[1024];
          for (int length = 0; (length = istrm_.read(buffer)) != -1; )
          {
              ostrm_.write(buffer, 0, length);
          }
      }
      catch (Exception e)
      {
          e.printStackTrace();
      }
  }
  private final OutputStream ostrm_;
  private final InputStream istrm_;
}
person Pepe    schedule 25.03.2011
comment
Хорошо, что ссылка недействительна, но кодов, скопированных здесь, достаточно. - person mrmoment; 23.06.2014
comment
@tvanfosson Привет, у меня есть одно сомнение! Это работает для «cmd», я не могу использовать это для «powershell». Есть ли обходной путь, которому я мог бы следовать? - person GP cyborg; 27.10.2014

Если вы хотите запустить несколько команд в оболочке cmd, вы можете создать одну команду следующим образом:

  rt.exec("cmd /c start cmd.exe /K \"cd c:/ && dir\"");

Эта страница объясняет больше.

person Vincent Ramdhanie    schedule 11.11.2010

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

Если вы хотите составить запросы, вам нужно будет сделать это в рамках одного вызова exec. Bash позволяет указывать несколько команд в одной строке, если они разделены точкой с запятой; Windows CMD может позволить то же самое, а если нет, то всегда есть пакетные сценарии.

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

String[] filenames = new java.io.File("C:/").list();
person Andrzej Doyle    schedule 11.11.2010
comment
@Boris - проверьте историю вопросов, она была отредактирована за два месяца с тех пор, как я опубликовал этот ответ. - person Andrzej Doyle; 18.01.2012

Попробуйте это ссылка

Вы не используете "cd" для изменения каталога, из которого запускаются ваши команды. Вам нужен полный путь к исполняемому файлу, который вы хотите запустить.

Кроме того, перечисление содержимого каталога проще сделать с помощью классов File/Directory.

person Piotr    schedule 11.11.2010
comment
Ответ не связан с вопросом - person Mert Serimer; 19.01.2016

Каждый из ваших вызовов exec создает процесс. Второй и третий вызовы не выполняются в том же процессе оболочки, который вы создали в первом. Попробуйте поместить все команды в bat-скрипт и запустить его одним вызовом: rt.exec("cmd myfile.bat"); или аналогичный

person Carles Barrobés    schedule 11.11.2010
comment
Ответ не относится к коду вопроса - другого вызова exec нет - person Boris Daich; 17.01.2012
comment
Было, когда я ответил, но с тех пор вопрос был отредактирован. Пожалуйста, ознакомьтесь с историей изменений для этого вопроса, прежде чем голосовать против. - person Carles Barrobés; 18.01.2012

Это потому, что каждый runtime.exec(..) возвращает класс Process, который следует использовать после выполнения, а не вызов других команд классом Runtime.

Если вы посмотрите на документ по процессу, вы увидите что вы можете использовать

  • getInputStream()
  • getOutputStream()

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

person Jack    schedule 11.11.2010

Запись в исходящий поток из процесса — неправильное направление. «вне» в этом случае означает от процесса к вам. Попробуйте получить/записать во входной поток для процесса и прочитать из выходного потока, чтобы увидеть результаты.

person Kelly S. French    schedule 11.11.2010

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

https://stackoverflow.com/a/24406721/3751590

Также см. «Обновление» в лучшем ответе для использования терминала Cygwin.

person singe3    schedule 25.06.2014

Вот более простой пример, не требующий нескольких потоков:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class SimplePty
{
    public SimplePty(Process process) throws IOException
    {
        while (process.isAlive())
        {
            sync(process.getErrorStream(), System.err);
            sync(process.getInputStream(), System.out);
            sync(System.in, process.getOutputStream());
        }
    }
    
    private void sync(InputStream in, OutputStream out) throws IOException
    {
        while (in.available() > 0)
        {
            out.write(in.read());
            out.flush();
        }
    }
    
    public static void main( String[] args ) throws IOException
    {
        String os = System.getProperty("os.name").toLowerCase();
        String shell = os.contains("win") ? "cmd" : "bash";
        Process process = new ProcessBuilder(shell).start();
        new SimplePty(process);
    }
}
person egerardus    schedule 22.10.2020

person    schedule
comment
Пожалуйста, добавьте некоторое объяснение к вашему ответу, чтобы другие могли извлечь из него уроки. - person Nico Haase; 22.10.2020