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

Bibliothèques, systèmes et outils C Discussion :

fonction system() sous windows avec des blancs, des arguments, etc.


Sujet :

Bibliothèques, systèmes et outils C

  1. #1
    Membre régulier
    Homme Profil pro
    chercheur
    Inscrit en
    Décembre 2012
    Messages
    195
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : chercheur

    Informations forums :
    Inscription : Décembre 2012
    Messages : 195
    Points : 84
    Points
    84
    Par défaut fonction system() sous windows avec des blancs, des arguments, etc.
    Bonjour,

    J'utilise fréquemment la fonction system() sous unix sans problème. Elle me pose des problèmes sous windows (appel de cmd.exe), car j'ai des blancs (white spaces) dans mes chemins et j'ai des arguments à rajouter. Je m'explique :

    Supposé que je veuille lancer "d:\mon repetoire\mon appli.exe" cinq fois avec un argument à chaque fois différent, comme par exemple :

    "d:\mon repetoire\mon appli.exe 1.0"
    "d:\mon repetoire\mon appli.exe 2.0"
    "d:\mon repetoire\mon appli.exe 3.0"
    "d:\mon repetoire\mon appli.exe 4.0"
    "d:\mon repetoire\mon appli.exe 5.0"

    Je reconstruits bien ces chaines de str dans une boucle que je passe à chaque fois à system(), avec les guillemets au début et à la fin, mais ca ne marche pas. En revanche, j'arrive bien à faire marcher ca si l'appli est lancée à chaque fois sans argument.

    En regardant la doc de cmd.exe, je vois bien que windows (par rapport à unix), se complique pas mal les pinceaux avec les guillemets. J'ai bien alors essayé de lancer plus explicitement "cmd.exe \S \C ..", mais ca ne marche toujours pas.

    J'ai également essayé des trucs comme :

    "d:\mon repetoire\mon appli.exe" "1.0", etc.

    Mais rien n'y fait.


    Quelqu'un aurait une idée ?

    D'avance merci pour toute aide sur ce point.

    Cordialement, Eric.

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 400
    Points : 23 777
    Points
    23 777
    Par défaut
    Bonjour,

    C'est normal, l'espace est considéré comme un séparateur d'arguments. Les guillemets servent justement à lier un bloc de caractères en une seule unité lexicale. Donc il faut mettre les guillemets autour du nom de ton application, ajouter un espace après le guillemet fermant, puis ajouter ton paramètre.

    Je suis quand même obligé de te signaler que si tu ne fais pas cela « pour l'exercice », alors tu cumules les mauvaises pratiques : coller des espaces dans un nom d'application, passer par system(), utiliser cette fonction sur différents systèmes d'exploitation…

    Il faut savoir aussi que DOS était écrit dès le départ pour être une pâle imitation des gros systèmes, et qu'il en a mimé l'interface qui était la norme à l'époque : la ligne de commande, et que Windows a ensuite été construit au dessus de cela. Cela veut dire que la manière dont cette ligne de commande a été gérée est très superficielle : par exemple, l'autocomplétion n'est prise en charge que par les versions relativement récentes de WIndows (je ne sais même plus si W2000 savait le faire). De la même façon, l'invite de commande est capable de comprendre elle-même quand les espaces font partie de la commande, de façon à ne pas perturber l'utilisateur, mais on ne sait pas du tout à quel niveau ce contrôle est géré. Si c'est par l'invite elle-même à la saisie, ça veut dire qu'un appel passé par system() ne profitera pas de cette fonctionnalité.

    De la même façon, « system() » sert en principe à envoyer une requête au système d'exploitation, c'est-à-dire à lui soumettre une commande telle que l'utilisateur aurait pu le faire, en proposant les mêmes services. Ça veut dire qu'une même chaîne va être interprétée complètement différemment d'un système à l'autre, et que cette interprétation va dépendre fortement de ton environnement. Si un alias est en vigueur, par exemple, il va modifier le comportement de la commande que tu appelles. Si c'est voulu, alors c'est un cas légitime de recours à system(), mais si tu comptes sur cette ligne pour rendre exactement le service tel qu'il l'a fait au moment où tu as écrit ton programme sur ta machine, alors non seulement ton programme sera buggé, mais il sera même percé : il souffrira d'une grave faille de sécurité puisqu'il sera très facile de faire à ton processus, en son nom, une action imprévue simplement en changeant le nom de la commande.

  3. #3
    Membre régulier
    Homme Profil pro
    chercheur
    Inscrit en
    Décembre 2012
    Messages
    195
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : chercheur

    Informations forums :
    Inscription : Décembre 2012
    Messages : 195
    Points : 84
    Points
    84
    Par défaut
    Merci pour votre réponse.

    Citation Envoyé par Obsidian Voir le message
    Bonjour,

    C'est normal, l'espace est considéré comme un séparateur d'arguments. Les guillemets servent justement à lier un bloc de caractères en une seule unité lexicale. Donc il faut mettre les guillemets autour du nom de ton application, ajouter un espace après le guillemet fermant, puis ajouter ton paramètre.

    Oui, ok, mais alors, pouquoi :

    "d:\mon repetoire\mon appli.exe" "1.0"

    (comme je mentionnais dans mon post) ne marche pas non plus?

    Il y a bien les guillemets aux bons endroits pour regrouper des blocs de caractères ?

    Il y a bien quelque chose qui ne va pas, ou que je ne comprends pas.

    Une (autre) explication ?

    D'avance merci encore pour votre temps,

    Eric.

  4. #4
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 195
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 195
    Points : 17 163
    Points
    17 163
    Par défaut
    Il faut que la chaine de caractère donnée en argument à la fonction système soit lisible par le shell windows.

    En gros, si "d:\mon repetoire\mon appli.exe" "1.0" est la commande que tu taperais dans la console windows, alors il faut que ce soit le contenu d'une unique chaine C.

    Ce qui donnerait la chaine "\"d:\mon repetoire\mon appli.exe\" \"1.0\"".

    La raison pour laquelle system("d:\mon repetoire\mon appli.exe" "1.0"); compile, c'est qu'en C, les chaines littérales successives sont compilées comme une seule chaine, constituée des deux parties par un unique espace.

  5. #5
    Membre régulier
    Homme Profil pro
    chercheur
    Inscrit en
    Décembre 2012
    Messages
    195
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : chercheur

    Informations forums :
    Inscription : Décembre 2012
    Messages : 195
    Points : 84
    Points
    84
    Par défaut
    Citation Envoyé par leternel Voir le message
    Il faut que la chaine de caractère donnée en argument à la fonction système soit lisible par le shell windows.

    En gros, si "d:\mon repetoire\mon appli.exe" "1.0" est la commande que tu taperais dans la console windows, alors il faut que ce soit le contenu d'une unique chaine C.

    Ce qui donnerait la chaine "\"d:\mon repetoire\mon appli.exe\" \"1.0\"".

    La raison pour laquelle system("d:\mon repetoire\mon appli.exe" "1.0"); compile, c'est qu'en C, les chaines littérales successives sont compilées comme une seule chaine, constituée des deux parties par un unique espace.
    Merci pour votre réponse,

    Malheureusement, il ne semble pas que ce soit la solution. D'abord, il y a les anti-slash "\m" qui sont reconnus, évidement, comme des caractère spéciaux. Ok, je les ai doublé. Je me retrouve donc avec l'instruction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    system("d:\\mon repetoire\\mon appli.exe" "1.0");
    Ou bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    system("\"d:\\mon repetoire\\mon appli.exe\"" "\"1.0\"");
    So far, so good. Les deux compilent effectivement, mais j'ai dans les deux cas le message d'erreur suivant :

    'd:\mon' n'est pas reconnu en tant que commande interne ou externe, un programme exécutable ou un fichier de commandes.

    Il y a donc bien un problème de gestion des blancs non résolu.

    Je profite de cette réponse pour reprendre une réponse de Obsidian

    Citation Envoyé par Obsidian Voir le message
    Je suis quand même obligé de te signaler que si tu ne fais pas cela « pour l'exercice », alors tu cumules les mauvaises pratiques : coller des espaces dans un nom d'application, passer par system(), utiliser cette fonction sur différents systèmes d'exploitation….
    Oui, évidement, mais ce n'est tout de même pas moi qui ai nommé des répertoires comme "Program Files (x86)".. On dirait que votre critique doit être dirigée vers les personnes qui ont codé Windows..
    Par ailleurs, où est le problème d'utiliser system() sur différents OS ? Je n'ai pas saisi la remarque ici. Vous avez d'autres solutions à proposer ?

    Je continus à penser, comme je l'avais signalé initialement, que la solution est dans le bon usage des arguments de la commande cmd.exe de Windows ("cmd.exe \S \C ..") mais je ne suis pas arrivé à faire fonctionner ceci correctement.

    Encore merci pour toute aide sur cette histoire de la gestion blancs avec la fonction system().

    Eric.

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 400
    Points : 23 777
    Points
    23 777
    Par défaut
    Re-bonjour,

    Citation Envoyé par eric1708 Voir le message
    Malheureusement, il ne semble pas que ce soit la solution. D'abord, il y a les anti-slash "\m" qui sont reconnus, évidement, comme des caractère spéciaux. Ok, je les ai doublé. Je me retrouve donc avec l'instruction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    system("d:\\mon repetoire\\mon appli.exe" "1.0");
    Ou bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    system("\"d:\\mon repetoire\\mon appli.exe\"" "\"1.0\"");
    So far, so good. Les deux compilent effectivement, mais j'ai dans les deux cas le message d'erreur suivant :

    'd:\mon' n'est pas reconnu en tant que commande interne ou externe, un programme exécutable ou un fichier de commandes.
    Attention : je suis parti du principe que tu avais construit une chaîne dans un buffer mais si tu l'as écrite directement ainsi, ça ne marchera pas non plus : le C interprète à la compilation les chaînes successives du style « "un" "deux" "trois" » comme une seule grande chaîne et concatène les morceaux. Les espaces entre les guillemets font partie des lexons du langage et pas de la chaîne proprement dite. Ici, on obtiendrait ainsi : « "undeuxtrois" ». Il fallait également gérer les anti-slashes interprétés par le C, comme tu l'as fait. Du coté de la ligne de commande, il semblerait que l'interpréteur ait du mal avec les guillemets. Tant pis.

    Essaie quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        system("d:\\ton repertoire\\ton appli.exe 1.0");
    Oui, évidement, mais ce n'est tout de même pas moi qui ai nommé des répertoires comme "Program Files (x86)".. On dirait que votre critique doit être dirigée vers les personnes qui ont codé Windows..
    Certes. Mais comme ce dépôt pourra lui-même évoluer avec les architectures ou en fonction de l'implémentation personnelle de l'utilisateur, le mieux est de s'appuyer sur les variables d'environnement proposées par le système : http://fr.wikipedia.org/wiki/Variabl...rogramFiles.25

    Par ailleurs, où est le problème d'utiliser system() sur différents OS ? Je n'ai pas saisi la remarque ici. Vous avez d'autres solutions à proposer ? Eric.
    Il y en a d'autres mais elles ne sont pas forcément plus simples à mettre en place et dépendent du contexte. Ce n'est pas tant utiliser la fonction elle-même sur différentes plate-formes qui pose problème puisqu'elle est définie par la bibliothèque standard du C lui-même et que c'est une des plus notoires. Le problème vient du fait que, comme dit plus haut, elle est par définition hautement dépendante du système d'exploitation lui-même. Donc, non seulement une commande n'est pas portable d'un OS à un autre mais même au sein d'une même famille, tu ne pourras jamais garantir à 100 % qu'elle aura l'effet escompté. Il faut simplement se souvenir que system() ne sert pas spécialement à lancer une application mais à faire interpréter une commande par le système d'exploitation, quelle qu'elle soit.

  7. #7
    Membre régulier
    Homme Profil pro
    chercheur
    Inscrit en
    Décembre 2012
    Messages
    195
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : chercheur

    Informations forums :
    Inscription : Décembre 2012
    Messages : 195
    Points : 84
    Points
    84
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Attention : je suis parti du principe que tu avais construit une chaîne dans un buffer mais si tu l'as écrite directement ainsi, ça ne marchera pas non plus : le C interprète à la compilation les chaînes successives du style « "un" "deux" "trois" » comme une seule grande chaîne et concatène les morceaux. Les espaces entre les guillemets font partie des lexons du langage et pas de la chaîne proprement dite. Ici, on obtiendrait ainsi : « "undeuxtrois" ». Il fallait également gérer les anti-slashes interprétés par le C, comme tu l'as fait. Du coté de la ligne de commande, il semblerait que l'interpréteur ait du mal avec les guillemets. Tant pis.
    Oui, oui, je passe bien par un buffer avant, que je construits dans une boucle, comme expliqué initialement. Ca ne fonctionne pas, donc.
    Citation Envoyé par Obsidian Voir le message
    Essaie quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        system("d:\\ton repertoire\\ton appli.exe 1.0");
    Marche pas non plus, avec le même message d'erreur.

    Oui, je sais, je me répète (j'ai un peu l'impression de ne pas être lu..):
    Citation Envoyé par eric1708 Voir le message
    Je continus à penser, comme je l'avais signalé initialement, que la solution est dans le bon usage des arguments de la commande cmd.exe de Windows ("cmd.exe \S \C ..") mais je ne suis pas arrivé à faire fonctionner ceci correctement.
    Je suis pratiquement sûr que la solution se trouve là (et par ailleurs, oui, je sais que system() ne sert pas à lancer une application mais à faire interpréter une commande par le système d'exploitation. C'est bien ca que ma remarque ci-dessus veut dire..).

    Encore merci pour toute aide sur cette histoire de gestion des blancs avec c la fonction system().

    Eric.

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Je viens d'examiner le code de la CRT de Microsoft, où system() fait un appel à cmd.exe /c, via CreateProcess().

  9. #9
    Membre régulier
    Homme Profil pro
    chercheur
    Inscrit en
    Décembre 2012
    Messages
    195
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : chercheur

    Informations forums :
    Inscription : Décembre 2012
    Messages : 195
    Points : 84
    Points
    84
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Je viens d'examiner le code de la CRT de Microsoft, où system() fait un appel à cmd.exe /c, via CreateProcess().
    Oui, merci. Ca confirme bien ce que je pensais/savais, mais ce ne me donne pas de solutions. La doc de cmd.exe parle explicitement de la manière de gérer les blancs, etc., mais je n'ai toujours pas réussi à faire tourner ceci correctement..

    Eric.

  10. #10
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Normalement, pour appeler statiquement "d:\mon repetoire\mon appli.exe 1.0", naïvement j'utiliserais ceci:
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    system("\"d:\\mon repetoire\\mon appli.exe\" 1.0"); //Avec optionnellement des guillemets échappés autour de 1.0
    Et donc, dans une boucle:
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    sprintf(buf, "\"d:\\mon repetoire\\mon appli.exe\" %f", valeur);
    system(buf);

  11. #11
    Membre régulier
    Homme Profil pro
    chercheur
    Inscrit en
    Décembre 2012
    Messages
    195
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : chercheur

    Informations forums :
    Inscription : Décembre 2012
    Messages : 195
    Points : 84
    Points
    84
    Par défaut
    Ok Médinoc, c'était effectivement la bonne solution. Et plusieurs arguments peuvent (enfin) être envoyés comme ca également.

    Félicitations! et merci.

    Eric.

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

Discussions similaires

  1. Déplacer des fichiers Excel sous Windows avec SAS
    Par Antoun dans le forum Outils BI
    Réponses: 6
    Dernier message: 19/11/2009, 17h05
  2. Réponses: 5
    Dernier message: 24/08/2009, 18h58
  3. Réponses: 9
    Dernier message: 29/04/2008, 13h38
  4. [Système] Lancer VLC avec system() sous windows
    Par madislak dans le forum Langage
    Réponses: 2
    Dernier message: 15/07/2007, 03h25
  5. [Système]Service windows avec java
    Par stephpr44 dans le forum Général Java
    Réponses: 4
    Dernier message: 24/11/2005, 20h50

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