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

Shell et commandes GNU Discussion :

Fonction bash dont un argument contient un caractère spécial


Sujet :

Shell et commandes GNU

  1. #1
    Membre régulier Avatar de YuGiOhJCJ
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2005
    Messages
    206
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2005
    Messages : 206
    Points : 114
    Points
    114
    Par défaut Fonction bash dont un argument contient un caractère spécial
    Bonjour,

    J'ai déjà ouvert une discussion [1] concernant une fonction bash appelée "execcmd" qui :
    • affiche le nom de la commande à lancer
    • lance la commande
    • affiche un message pour dire si la commande a réussi ou échoué


    La solution qui ne fonctionne pas est de stocker la commande à lancer dans une variable. Puis d'exécuter la commande à l'aide de cette variable.
    La solution qui fonctionne est de stocker la commande à lancer dans les paramètres de la fonction. Puis d'exécuter la commande à l'aide de "$@".

    Mais j'ai remarqué un problème lorsque l'on souhaite passer une commande qui contient des caractères spéciaux comme le ">", ">>" ou encore le "|".
    Dans ce cas, ces caractères ne sont pas considérés comme des arguments de la fonction.

    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    execcmd echo '#!/bin/bash' > /tmp/toto.txt
    Résultat (à l'affichage) :
    rien du tout ! (car le flux est redirigé vers le fichier)

    Résultat (dans le fichier) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $ cat /tmp/toto.txt 
    executing the 'echo #!/bin/bash' command... Done.
    Pour résoudre ce problème, on peut utiliser la double quote "...".
    Mais dans ce cas, le symbole perd toute sa fonctionnalité dans la commande et devient une chaine de caractères ordinaire...

    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    execcmd echo '#!/bin/bash' ">" /tmp/toto.txt
    Résultat (à l'affichage) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    executing the 'echo #!/bin/bash > /tmp/toto.txt' command... Done.
    Résultat (dans le fichier) :
    le fichier /tmp/toto.txt n'existe pas !

    Est-ce que vous voyez une solution pour que la commande passée en arguments à la fonction soit prise en compte correctement ?

    Merci.

    [1] http://www.developpez.net/forums/d12...s-script-bash/

  2. #2
    Rédacteur

    Avatar de ok.Idriss
    Homme Profil pro
    IS Consultant
    Inscrit en
    Février 2009
    Messages
    5 220
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : IS Consultant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2009
    Messages : 5 220
    Points : 19 452
    Points
    19 452
    Par défaut
    Bonsoir.

    N_BaH va encore me taper dessus (Sve@r au secours ) mais bon j'avance quand même ma solution qui fonctionne à défaut de trouver mieux : eval .

    Démonstration :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    [idriss@hp-dv6:~]$ cat test.sh
    #!/bin/bash
     
    executeCmd(){
        echo "executing the '$@' command... "
        eval "$@"
    }
     
    executeCmd $@
    [idriss@hp-dv6:~]$ ./test.sh echo "salut" ">" test.txt
    executing the 'echo salut > test.txt' command... 
    [idriss@hp-dv6:~]$ cat test.txt 
    salut
    [idriss@hp-dv6:~]$
    Si quelqu'un propose quelque chose de mieux et de plus sûr tant mieux mais au moins tu as déjà une solution fonctionnelle. Personnellement eval ne m'a jamais posé de soucis et ça reste très pratique dans beaucoup de cas, notamment pour ces histoires de méta-caractères.

    Par exemple lors de sed construits dynamiquement où je concatène des expressions régulières de substitions ou la wildcard apparaît, j'ai souvent recours à eval lors de l'exécution finale afin d'éviter que bash interprète * comme la liste des fichiers du répertoire courant. Jusqu'ici j'en suis totalement satisfait.

    Cordialement,
    Idriss

  3. #3
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 552
    Points : 19 392
    Points
    19 392
    Par défaut
    Il faut bien se souvenir de ce que fait cette commande :
    Citation Envoyé par help eval
    Exécute des arguments comme s'ils étaient une commande du shell.
    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  4. #4
    Rédacteur

    Avatar de ok.Idriss
    Homme Profil pro
    IS Consultant
    Inscrit en
    Février 2009
    Messages
    5 220
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : IS Consultant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2009
    Messages : 5 220
    Points : 19 452
    Points
    19 452
    Par défaut
    Exécute des arguments comme s'ils étaient une commande du shell.
    Ben à moins que j'ai mal compris, c'est un peu ce que cherche à faire YuGiOhJCJ avec sa fonction execcmd ?

  5. #5
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 552
    Points : 19 392
    Points
    19 392
    Par défaut
    c'est pour ça que je n'ai pas dégainé mon fouet
    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  6. #6
    Rédacteur

    Avatar de ok.Idriss
    Homme Profil pro
    IS Consultant
    Inscrit en
    Février 2009
    Messages
    5 220
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : IS Consultant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2009
    Messages : 5 220
    Points : 19 452
    Points
    19 452
    Par défaut
    Bon beh ça prouve que eval c'est pas toujours evil


  7. #7
    Membre régulier Avatar de YuGiOhJCJ
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2005
    Messages
    206
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2005
    Messages : 206
    Points : 114
    Points
    114
    Par défaut
    Malheureusement, il suffit qu'un "#" se situe au début d'un argument pour que ça ne fonctionne plus.

    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $ ./test.sh echo "#salut" ">" test.txt 
    executing the 'echo #salut > test.txt' command...
    Résultat (dans le fichier):
    le fichier n'est pas créé !

    Comment faire en cas de "#" en début d'argument ?

  8. #8
    Rédacteur

    Avatar de ok.Idriss
    Homme Profil pro
    IS Consultant
    Inscrit en
    Février 2009
    Messages
    5 220
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : IS Consultant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2009
    Messages : 5 220
    Points : 19 452
    Points
    19 452
    Par défaut
    Bonjour.

    Le plus simple c'est d'échapper tes # je pense. Si ça vient d'un fichier, un sed fera l'affaire ... si c'est écrit en dur dans le script, les échapper à la main devrait faire l'affaire aussi.

    Cordialement,
    Idriss

  9. #9
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 287
    Points : 12 744
    Points
    12 744
    Par défaut
    Bonjour,
    Voici une autre façon possible pas très conventionnelle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    executeCmd ()
    {
        CMD=`history | tail -1 | sed -e 's/^[ 0-9]*[[:graph:]]* *//g'`;
        echo "executing the '$CMD' command" > /dev/tty;
        eval $CMD
    }
    et ici, tu peux directement entrer une commande du type:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    executeCmd echo "#salut" >test.txt
    Pour pouvoir l'utiliser dans un script bash, il faut activer l'historique dans le script:
    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
    $ cat test1.sh
    #!/bin/bash
    set -o history
    executeCmd(){
    CMD=`history | tail -1 | sed -e 's/^[ 0-9]*[[:graph:]]* *//g'`
    echo "executing the '$CMD' command" >/dev/tty
    eval $CMD
    }
    executeCmd ls
    executeCmd ls -l
    executeCmd ls -l >res.txt
    $ ./test1.sh
    executing the 'ls' command
    fichier.tx  res.txt  test1.sh  test.txt
    executing the 'ls -l' command
    total 3
    -rw-rw-r-- 1 xxxxxx xxxxxx  22 Mar 11 15:26 fichier.tx
    -rw-rw-r-- 1 xxxxxx xxxxxx   0 Mar 13 13:38 res.txt
    -rwx------ 1 xxxxxx xxxxxx 220 Mar 13 13:47 test1.sh
    -rw-rw-r-- 1 xxxxxx xxxxxx   7 Mar 13 13:40 test.txt
    executing the 'ls -l >res.txt' command
    $ cat res.txt
    total 3
    -rw-rw-r-- 1 xxxxxx xxxxxx  22 Mar 11 15:26 fichier.tx
    -rw-rw-r-- 1 xxxxxx xxxxxx   0 Mar 13 13:47 res.txt
    -rwx------ 1 xxxxxx xxxxxx 220 Mar 13 13:47 test1.sh
    -rw-rw-r-- 1 xxxxxx xxxxxx   7 Mar 13 13:40 test.txt
    Cordialement.
    Cordialement.

  10. #10
    Membre régulier Avatar de YuGiOhJCJ
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2005
    Messages
    206
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2005
    Messages : 206
    Points : 114
    Points
    114
    Par défaut
    Quand je lis le man de "tail" je ne vois pas l'option "-1".
    Mais il semblerait que ça a le même fonctionnement que "tail -n 1".
    Au lieu d'afficher les 10 dernières lignes, ça affiche une seule ligne.
    Ouais jouer avec l'historique ça peut être intéressant aussi.

    Et l'échappement ça fonctionne.
    Ce qui est dommage avec l'échappement c'est que l'utilisateur de mon script va devoir penser à échapper tous ses caractères ce qui n'est pas vraiment acceptable...
    Si à la place du "#", c'est "$@" alors je cois qu'il doit échapper ainsi "\$\@".
    C'est assez horrible ^^

    C'est pareil chez vous, vous ne voyez pas l'option "-1' dans le man de "tail" ?

    Je pense que je vais me contenter d'échapper mes caractères... Problème résolu.

  11. #11
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 101
    Points : 5 849
    Points
    5 849
    Par défaut
    Citation Envoyé par YuGiOhJCJ Voir le message
    Malheureusement, il suffit qu'un "#" se situe au début d'un argument pour que ça ne fonctionne plus.

    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $ ./test.sh echo "#salut" ">" test.txt 
    executing the 'echo #salut > test.txt' command...
    Résultat (dans le fichier):
    le fichier n'est pas créé !

    Comment faire en cas de "#" en début d'argument ?
    à vérifier, mais j'aurais plutôt quoté l'ensemble:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $ ./test.sh 'echo "#salut" > test.txt'
    Du coup, il n'y a plus de guillemets autour du '>'.

    Normalement ça devrait marcher! mais, si l'utilisateur a des variables non exportées, elles ne seront pas prises en compte...

  12. #12
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 101
    Points : 5 849
    Points
    5 849
    Par défaut
    Citation Envoyé par YuGiOhJCJ Voir le message
    Quand je lis le man de "tail" je ne vois pas l'option "-1".
    Mais il semblerait que ça a le même fonctionnement que "tail -n 1".
    Au lieu d'afficher les 10 dernières lignes, ça affiche une seule ligne.
    C'est pareil chez vous, vous ne voyez pas l'option "-1' dans le man de "tail" ?

    Je pense que je vais me contenter d'échapper mes caractères...
    C'est une très vieille manière d'écrire qui marche avec n'importe quel nombre et qui semble ne plus être documenté dans les man que j'ai sous la main:
    tail -1 file est équivalent à tail -n 1 file.
    tail -20 fileest équivalent à tail -n 20 file.

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

Discussions similaires

  1. Réponses: 8
    Dernier message: 13/06/2015, 15h03
  2. [XL-2007] Fonction dont les arguments sont une partie d'un code URL
    Par Vince006 dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 30/04/2012, 00h29
  3. Verifier qu'un champ ne contient aucun caractère spécial
    Par aemilia26 dans le forum Collection et Stream
    Réponses: 5
    Dernier message: 23/02/2010, 11h19
  4. parametre de formulaire dont la valeur contient de caractères spéciaux
    Par jakouz dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 26/04/2006, 14h29
  5. fonction dont les argument sont dans un dico
    Par GConstant dans le forum Général Python
    Réponses: 1
    Dernier message: 12/08/2004, 18h24

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