Domanda

Esiste un modo per eseguire periodicamente un comando Unix ( ps nel mio caso) in Java? Il ciclo che ho scritto:

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();
        }
    }
}

non funziona. Funziona perfettamente bene la prima volta, ma ci sono 0 byte disponibili dal flusso di input ogni volta dopo. Proverei il comando watch , ma questa scatola di Solaris non lo possiede. Non riesco a utilizzare un lavoro cron poiché devo sapere se il PID è presente nell'applicazione Java. Qualche idea?

Grazie in anticipo.

EDIT: impossibile usare cron job

EDIT: sto realizzando un nuovo Thread dello stesso tipo (PS) dopo la sua conclusione, quindi sicuramente creerò un nuovo ProcessBuilder ogni volta.

EDIT: ho inserito il loop che non ha funzionato poiché ha causato confusione.

È stato utile?

Soluzione

Non sono sicuro di dove sia il ciclo, ma dovrai creare un nuovo oggetto Proc (e quindi un nuovo InputStream ) ogni volta attraverso il ciclo. Altrimenti guarderai sempre il risultato alla prima chiamata. I javadocs per ProcessBuilder indicano che non è necessario crearne uno ogni volta.

Potrebbe esserci anche una condizione di competizione in cui il flusso di input non è ancora pronto quando si chiamak available () . Dovresti assicurarti che il flusso di input abbia raggiunto EOF (che accadrà con ps, anche se non con, diciamo, in alto) prima di stampare i risultati.

Inoltre non stai gestendo correttamente la codifica, anche se non so che tipo di codifica l'output di " ps " è (al di fuori di ASCII). Dal momento che " ps " è probabilmente ASCII questo è ragionevolmente sicuro, ma potrebbe non essere per altri comandi (e per altri flussi di input).

Altri suggerimenti

Oltre alla risposta di Kathy, dovresti anche raccogliere stdout e stderr in thread separati per ogni invocazione. Altrimenti il ??processo si bloccherà in attesa che tu legga questi dati.

Vedi questa risposta per maggiori dettagli.

EDIT. Stai chiamando waitFor () per raccogliere lo stato di uscita? Il modo in cui mi approccerei normalmente è quello di eseguire e quindi chiamare waitFor () . Penso che destroy () possa essere ridondante in questo contesto.

Quindi penso che il problema sia che stai controllando il flusso di input prima della fine dell'esecuzione di ps. Prova ad aggiungere:

proc.waitFor ()

prima di chiamare osInput.available ().

Ecco come l'avrei implementato:

    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);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top