Повторите команду Unix в Java - PullRequest
2 голосов
/ 24 июня 2009

Есть ли способ периодически запускать команду Unix (ps в моем случае) в 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. Есть идеи?

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

РЕДАКТИРОВАТЬ: не может использовать задание cron

РЕДАКТИРОВАТЬ: я делаю новый Thread того же типа (PS) после его завершения, так что я определенно создаю новый ProcessBuilder каждый раз.

РЕДАКТИРОВАТЬ: Я поместил цикл, который не работал обратно, так как это вызвало путаницу.

Ответы [ 3 ]

3 голосов
/ 24 июня 2009

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

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

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

1 голос
/ 24 июня 2009

Так что я думаю, что проблема в том, что вы проверяете поток ввода до конца выполнения 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);
1 голос
/ 24 июня 2009

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

См. этот ответ для более подробной информации.

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

...