IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Entrée/Sortie Java Discussion :

Problème exécution shell


Sujet :

Entrée/Sortie Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut Problème exécution shell
    Salut,

    J'essaie de lancer un petit script shell en java (non contenu dans un fichier) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for i in 'a b'; do echo $i; done
    qui devrait évidemment afficher a b.

    Mais voilà, je n'y arrive pas.

    Voici mes tests :
    test1 : montre que pour les commandes ça marche direct (echo)
    test2 : montre que pour les boucles, ça n'est pas si simple...
    test3 : même avec sh -c devant...
    test4 : ou en mettant le script sur stdin (comme on le fait dans un shell)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    import java.io.PrintWriter;
    import java.util.Scanner;
     
    public class TestIO {
     
    	static interface Test {
    		void test() throws Exception;
    	}
     
    	public static void main(String... args) throws Exception {
    		Test test1 = new Test() {
    			@Override
    			public void test() throws Exception {
    				String command = "echo bonjour";
    				Process process = Runtime.getRuntime().exec(command);
    				Scanner scanner = new Scanner(process.getInputStream());
    				while (scanner.hasNextLine()) {
    					String line = scanner.nextLine();
    					System.out.println(line);
    				}
    			}
    		};
    		Test test2 = new Test() {
    			@Override
    			public void test() throws Exception {
    				String command = "for i in 'a b'; do echo $i; done";
    				Process process = Runtime.getRuntime().exec(command);
    				Scanner scanner = new Scanner(process.getInputStream());
    				while (scanner.hasNextLine()) {
    					String line = scanner.nextLine();
    					System.out.println(line);
    				}
    			}
    		};
    		Test test3 = new Test() {
    			@Override
    			public void test() throws Exception {
    				String command = "sh -c \"for i in 'a b'; do echo $i; done\"";
    				Process process = Runtime.getRuntime().exec(command);
    				Scanner scanner = new Scanner(process.getInputStream());
    				while (scanner.hasNextLine()) {
    					String line = scanner.nextLine();
    					System.out.println(line);
    				}
    			}
    		};
    		Test test4 = new Test() {
    			@Override
    			public void test() throws Exception {
    				String command = "sh";
    				Process process = Runtime.getRuntime().exec(command);
    				PrintWriter writer = new PrintWriter(process.getOutputStream());
    				writer.println("for i in 'a b'; do echo $i; done");
    				Scanner scanner = new Scanner(process.getInputStream());
    				System.out.println("before hasNextLine()");
    				while (scanner.hasNextLine()) {
    					System.out.println("after hasNextLine()");
    					String line = scanner.nextLine();
    					System.out.println(line);
    				}
    			}
    		};
    		Test[] tests = { test1, test2, test3, test4 };
    		for (int i = 0; i < tests.length; i++) {
    			try {
    				System.out.println("==== DEBUT TEST " + i + " ====");
    				tests[i].test();
    			} catch (Exception e) {
    				System.err.println("test " + i + " failed");
    				e.printStackTrace();
    			} finally {
    				System.out.println("==== FIN TEST " + i + " ====");
    				Thread.sleep(1000);
    			}
    		}
    	}
     
    }
    Et le résultat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    ==== DEBUT TEST 0 ====
    bonjour
    ==== FIN TEST 0 ====
    ==== DEBUT TEST 1 ====
    test 1 failed
    java.io.IOException: Cannot run program "for": java.io.IOException: error=2, No such file or directory
    	at java.lang.ProcessBuilder.start(ProcessBuilder.java:474)
    	at java.lang.Runtime.exec(Runtime.java:610)
    	at java.lang.Runtime.exec(Runtime.java:448)
    	at java.lang.Runtime.exec(Runtime.java:345)
    	at TestIO$2.test(TestIO.java:27)
    	at TestIO.main(TestIO.java:67)
    Caused by: java.io.IOException: java.io.IOException: error=2, No such file or directory
    	at java.lang.UNIXProcess.<init>(UNIXProcess.java:164)
    	at java.lang.ProcessImpl.start(ProcessImpl.java:81)
    	at java.lang.ProcessBuilder.start(ProcessBuilder.java:467)
    	... 5 more
    ==== FIN TEST 1 ====
    ==== DEBUT TEST 2 ====
    ==== FIN TEST 2 ====
    ==== DEBUT TEST 3 ====
    before hasNextLine()
    Comment faire alors?

  2. #2
    Membre Expert
    Homme Profil pro
    Dév. Java & C#
    Inscrit en
    Octobre 2002
    Messages
    1 414
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Dév. Java & C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2002
    Messages : 1 414
    Par défaut
    Bonjour

    Est-ce que ton script fonctionne?

    Car dans l'environnement de ma machine
    $ uname -a
    CYGWIN_NT-5.1 XXXXX 1.5.25(0.156/4/2) 2008-03-05 19:27 i686 Cygwin

    $ sh --version
    sh --version
    GNU bash, version 3.2.33(18)-release (i686-pc-cygwin)
    Copyright (C) 2007 Free Software Foundation, Inc.

    J'ai ce résultat:
    $ sh -c "for i in 'a b'; do echo $i; done"

    et sur une autre machine
    [jowo@host ~]$ uname -a
    FreeBSD XXXX 6.1-STABLE FreeBSD 6.1-STABLE #4: Fri Nov 16 15:55:04 CET 2007 YYYYY i386

    [jowo@host ~]$ sh -c "for i in 'a b'; do echo $i; done"


    Rien n'est affiché.

  3. #3
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Certes, mais par contre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for i in 'a b'; do echo $i; done
    fonctionne (évidemment)
    Je voudrais juste appeler ce code dans un programme java.

  4. #4
    Membre Expert
    Homme Profil pro
    Dév. Java & C#
    Inscrit en
    Octobre 2002
    Messages
    1 414
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Dév. Java & C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2002
    Messages : 1 414
    Par défaut
    Le for "fonctionne" car tu es directement sous un shell.

    Pour "simuler" le comportement sous Java il faut démarrer un shell avec une commande par exemple sh ou bash

    jowo@host ~
    $ sh -c 'for i in "a b"; do echo $i; done'
    a b

    jowo@host ~
    $ sh -c 'for i in a b; do echo $i; done'
    a
    b

    en Java
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    Test testJowo = new Test() {
    			@Override
    			public void test() throws Exception {
    				String command = "sh -c 'for i in \"a b\"; do echo $i; done'";
    				Process process = Runtime.getRuntime().exec(command);
    				Scanner scanner = new Scanner(process.getInputStream());
    				while (scanner.hasNextLine()) {
    					String line = scanner.nextLine();
    					System.out.println(line);
    				}
    			}
    		};

  5. #5
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Ah mais jsuis c**, c'était une histoire de guillements, avec les " il remplace $i par sa valeur (donc rien), d'où le problème

    Merci

  6. #6
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,

    Citation Envoyé par ®om Voir le message
    test1 : montre que pour les commandes ça marche direct (echo)
    Ce n'est pas tout à fait vrai...

    En fait il faut déjà comprendre qu'il y a 3 grands types de commandes :
    • Les mots-clefs du shell (for, while, if, then, ...)
    • Les commandes builtins (ou primitives), qui sont intégrés dans le shell pour plus de performance ou car elles ont un lien très fort avec le shell (par exemple : cd, pwd, echo, test, source, alias, bg, exit...).
    • Les applications autonomes (présente sur le disque), comme c'est le cas de la plupart des commandes (grep, awk, etc...)


    La classe Runtime permet d'appeler des applications autonomes, et ne peut donc pas utiliser directement les deux premiers type de commande.

    Toutefois, certaines builtins existent également en application autonome (comme /bin/echo ou /usr/bin/test), ce qui fait que ton test1 fonctionne, mais ce ne serait pas le cas sous Windows (il n'y a pas de "programme" echo.

    Citation Envoyé par ®om Voir le message
    test2 : montre que pour les boucles, ça n'est pas si simple...
    Les boucles nécessites un shell, et Runtime exécute un programme physique dans le PATH. Ici il ne trouve pas le programme for puisqu'il n'existe pas
    Citation Envoyé par ®om Voir le message
    test3 : même avec sh -c devant...
    Comme je l'ai dit Runtime appelle un simple programme, et le découpage ne fonctionne pas exactement comme celui du shell, ce qui fait qu'on peut avoir des incohérences car le programme ne recoit pas exactement la même chose.
    Le plus sûr étant de bien découpé soit même les différents paramètres :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     String[] commands = {"sh", "-c", "for i in 'a b'; do echo $i; done"};
     Process process = Runtime.getRuntime().exec(commands);
    Citation Envoyé par ®om Voir le message
    test4 : ou en mettant le script sur stdin (comme on le fait dans un shell)
    Ce n'est pas exactement comme on le fait dans un shell.

    Le shell fait bien la distinction entre ce qui lui arrive par un vrai terminal, et ce qui lui arrive directement en entrée comme dans ce cas (ou via un pipe par exemple). Il essayes de lire la totalité du flux avant de l'interpréter.

    Et on en vient au principal problème de ton code : la mauvaise gestion des flux.

    Comme tu ne fermes pas le flux d'entrée, le shell ne reçoit pas d'EOF et attend infiniment avant d'exécuter son traitement. De ton coté tu attends la réponse du shell avant de finir ton traitement : les deux programmes s'attendent mutuellement deadlock !



    Chaque process est associé avec 3 flux (stdin, stdout et stderr), et tu doit les traiters tous (depuis des threads différents), ou les fermer au plus tôt si tu les ignores... sinon tu risques ce genre de petit problème...


    Plus d'info :


    a++

  7. #7
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Merci adiGuba pour ton explication détaillée, j'opte pour .exec("sh","-c","lacommande");

  8. #8
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    J'ai une nouvelle question à ce sujet

    Si j'exécute un programme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    {"sh", "-c", "monprogramme"}
    c'est très bien, ça fonctionne.

    Maintenant si je veux exécuter un script, ça dépend pour quel shell il est prévu :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #!/bin/bash
    echo -e "bonjour\nau revoir"
    est différent de :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #!/bin/sh
    echo -e "bonjour\nau revoir"
    Dans une console, si on l'exécute, ça utilise automatiquement le bon (défini sur la première ligne).

    Mais pour l'appeler en java, comment faire pour choisir le bon shell (autrement qu'en analysant la première ligne si les 2 premiers caractères sont "#!")?

  9. #9
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Théoriquement cela devrait fonctionner (pas pu tester).

    Le sh -c sert à interpréter la commande (caractères spéciaux, variables d'environnements, redirections). Puis comme tu appelles un script il lancera le shell correspondant pour exécuter le code...

    Tu pourrais bien sûr te passer du sh -c si et seulement si tu es sûr que "monprogramme" ne correspond pas à une ligne de commande mais seulement au nom du script...

    a++

  10. #10
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Ah oui, effectivement, j'avais testé, mais il y avait une petite coquille dans mon test

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. problème exécutable matlab avec shell
    Par guefrachi dans le forum VB 6 et antérieur
    Réponses: 0
    Dernier message: 19/10/2010, 13h59
  2. [PHP-JS] Problème exécution fonction php avec js
    Par cokilulu dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 15/03/2006, 21h34
  3. Réponses: 4
    Dernier message: 09/12/2005, 22h17
  4. []Problème de SHELL
    Par laurentfrancis dans le forum VB 6 et antérieur
    Réponses: 4
    Dernier message: 08/10/2005, 19h41
  5. [VB.NET] Problème exécution en mode release.
    Par leSeb dans le forum Windows Forms
    Réponses: 2
    Dernier message: 07/01/2005, 17h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo