2009-06-24 7 views
2

Existe-t-il un moyen d'exécuter périodiquement une commande Unix (ps dans mon cas) en Java? La boucle que j'ai écrite:Répéter une commande Unix en 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(); 
     } 
    } 
} 

ne fonctionne pas. Il fonctionne parfaitement bien la première fois, mais il y a 0 octets disponibles à partir du flux d'entrée chaque fois après cela. Je vais essayer la commande watch, mais cette boîte Solaris n'a pas cela. Je ne peux pas utiliser un travail cron car j'ai besoin de savoir si le PID est là dans l'application Java. Des idées?

Merci d'avance.

EDIT: ne peut pas utiliser Cron emploi

EDIT: Je fais une nouvelle Thread du même type (PS) après conclut, donc je fais sans aucun doute une nouvelle ProcessBuilder chaque fois.

EDIT: J'ai mis la boucle qui n'a pas fonctionné car cela a causé de la confusion.

+0

Je ne vois pas une boucle. –

+0

remettre la boucle pour éviter toute confusion – geowa4

Répondre

3

Je ne suis pas certain où la boucle est, mais vous devrez créer un nouvel objet Proc (et donc un nouveau InputStream) à chaque fois à travers la boucle. Sinon, vous regarderez toujours le résultat au premier appel. Les javadocs pour ProcessBuilder indiquent que vous n'avez pas besoin d'en créer un à chaque fois.

Il peut également y avoir une condition de concurrence où le flux d'entrée n'est pas encore prêt lorsque vous appelez available(). Vous devriez vous assurer que le flux d'entrée a atteint EOF (ce qui arrivera avec ps, mais pas avec, disons, top) avant d'imprimer les résultats.

Vous ne gérez pas correctement le codage, bien que je ne connaisse pas le type de codage de la sortie de "ps" (en dehors de ASCII). Comme "ps" est probablement ASCII, il est raisonnablement sûr, mais peut ne pas l'être pour d'autres commandes (et pour d'autres flux d'entrée).

+0

ouais, je fais un nouveau processus à chaque fois. avez-vous lu le code? – geowa4

+0

mettre la boucle qui ne marche pas dans pour éviter la confusion – geowa4

+0

Le code n'a pas eu une boucle claire (avant l'édition), étant donné qu'il n'était pas clair quelles étaient les limites de la méthode –

1

En plus de la réponse de Kathy, vous devriez également rassembler stdout et stderr dans des threads séparés pour chaque invocation. Sinon, le processus bloquera l'attente de la lecture de ces données.

Voir this answer pour plus de détails.

EDIT. Appellez-vous au waitFor() pour obtenir un statut de sortie? La façon dont j'aborderais normalement ceci est d'exécuter et ensuite appeler waitFor(). Je pense que destroy() peut être redondant dans ce contexte.

+0

l'ai eu. Merci pour le conseil! J'ai appelé waitFor() juste après avoir démarré le processus – geowa4

1

Donc je pense que le problème est que vous vérifiez le flux d'entrée avant la fin de l'exécution ps. Essayez d'ajouter:

proc.waitFor()

avant d'appeler osInput.available().

Voici comment j'aurais implémenté:

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); 
Questions connexes