2009-06-24 6 views
2

Есть ли способ периодически запускать команду Unix (ps в моем случае) в Java? Цикл я написал:Repeat Unix Command в Java

while(this.check) 
{ 
    try 
    { 
      ProcessBuilder pb = new ProcessBuilder("ps"); 
      Process proc; 

      System.out.println(" * * Running `ps` * * "); 

      byte[] buffer; 
      String input; 

      proc = pb.start(); 
      BufferedInputStream osInput = 
       new BufferedInputStream(proc.getInputStream()); 

      //prints 0 every time after the first 
      System.out.println(osInput.available()); 

      buffer = new byte[osInput.available()]; 
      osInput.read(buffer); 
      input = new String(buffer); 
      for(String line : input.split("\n")) 
      { 
       if(line.equals("")) 
        continue; 
       this.handlePS(line); 
      } 

      proc.destroy(); 
      try 
      { 
       Thread.sleep(10000); 
      } 
      catch (InterruptedException ie) 
      { 
       ie.printStackTrace(); 
      } 
     } 
     catch (IOException ioe) 
     { 
      ioe.printStackTrace(); 
     } 
    } 
} 

не работает. Он работает отлично в первый раз, но после этого из входного потока поступает 0 байтов. Я бы попробовал команду watch, но в этом окне Solaris этого нет. Я не могу использовать задание cron, так как мне нужно знать, есть ли PID в Java-приложении. Есть идеи?

Заранее спасибо.

EDIT: не может использовать хрон

EDIT: Я готовлю новую Thread одного и того же типа (PS) после того, как он приходит к выводу, так что я определенно делает новую ProcessBuilder каждый раз.

EDIT: Я положил цикл, который не работал, поскольку он вызвал путаницу.

+0

Я не вижу петлю. –

+0

верните петлю во избежание путаницы – geowa4

ответ

3

Я не уверен, где цикл, но вам нужно будет создать новый объект Proc (и, следовательно, новый InputStream) каждый раз через цикл. В противном случае вы всегда будете смотреть на результат на первый вызов. В javadocs для ProcessBuilder указано, что вам не нужно создавать один из них каждый раз.

Также может быть состояние гонки, когда входной поток еще не готов, когда вы вызываете available(). Вы должны убедиться, что входной поток достиг EOF (что произойдет с ps, хотя и не с, скажем, сверху) перед печатью результатов.

Вы также не обрабатываете кодировку правильно, хотя я не знаю, какая кодировка выводит «ps» (вне ASCII). Поскольку «ps», вероятно, ASCII, это достаточно безопасно, но может и не быть для других команд (и для других входных потоков).

+0

Да, я делаю новый процесс каждый раз. Вы читали код? – geowa4

+0

помещает цикл, который не работает, чтобы избежать путаницы. – geowa4

+0

Код не имел четкого цикла (до редактирования), учитывая, что было непонятно, какие границы метода были –

1

В дополнение к ответу Кэти, вы также должны собирать stdout и stderr в отдельных потоках для каждого вызова. В противном случае процесс блокирует ожидание чтения этих данных.

Для получения более подробной информации см. this answer.

EDIT. Вы звоните waitFor(), чтобы собрать любой статус выхода? Как обычно я подхожу к этому, нужно выполнить, а затем позвонить waitFor(). Я думаю, destroy() может быть избыточным в этом контексте.

+0

получил это. Спасибо за совет! Я действительно вызвал waitFor() сразу после того, как начал процесс – geowa4

1

Поэтому я считаю, что проблема в том, что вы проверяете входной поток до конца выполнения ps. Попробуйте добавить:

proc.waitFor()

перед вызовом osInput.available().

Вот как я бы реализовал его:

TimerTask task = new TimerTask() { 

     private void work() throws Exception { 
      System.out.println("Now"); 
      ProcessBuilder pb = new ProcessBuilder("ps"); 
      Process p = pb.start(); 
      p.waitFor(); 
      BufferedReader reader 
       = new BufferedReader(new InputStreamReader(p.getInputStream())); 
      String line; 
      while ((line = reader.readLine()) != null) { 
       // Process line 
       System.out.println(line); 
      } 
     } 

     @Override 
     public void run() { 
      try { 
       work(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    }; 

    Timer timer = new Timer(); 
    long period = 5000; 
    timer.scheduleAtFixedRate(task, 0, period);