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 :

Regex en argument


Sujet :

Shell et commandes GNU

  1. #1
    Membre éclairé
    Inscrit en
    Décembre 2010
    Messages
    258
    Détails du profil
    Informations forums :
    Inscription : Décembre 2010
    Messages : 258
    Par défaut Regex en argument
    Bonsoir à tous,

    J'ai créer un petit script qui récupère une liste de noms de serveurs, et j'aimerai pouvoir passer un argument en regex pour filtrer la liste.
    Exemple, du fichier en entrée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    dvdsid04
    dvdsid05
    dv20b01
    db20b02
    Je tape la commande :
    J'aimerai que la sortie soit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    dvdsid04
    dvdsid05
    Voici mon code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    while read HOST
    do
    	# Si la ligne n'est pas vide		
    	if [ ! -z "$HOST" ]
    	then
    		# Application de la regex
    		if [[ "$HOST" =~ $1 ]]
    		then
    			echo "$HOST"
    		fi
    	fi
    done < "$SOL"
    Or, la sortie de mon script est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    dvdsid04
    dvdsid05
    dv20b01
    Pourquoi ?
    J'aimerai, logiquement avoir tout ce qui commence par dvd.
    Merci pour votre aide

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 644
    Par défaut
    Bonjour,

    ta regex signifie : toute chaîne qui commence par dv, suivie de zéro, un ou plusieurs d.
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  3. #3
    Expert confirmé Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 988
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 988
    Par défaut
    Tu confonds la syntaxe des regex avec celle de glob.

    dvd* pour glob signifie bien "dvd" suivie de n'importe quoi d'autre, alors que pour une regex il signifie "dv" suivie de la lettre "d" répétée 0 ou x fois.

    Donc ta commande devrait être simplement: ./my_script.sh ^dvd

  4. #4
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    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 102
    Par défaut
    Vous faites comme vous voulez, mais j'ai pris l'habitude de automatiquement et sans réfléchir mettre entre apostrophes les regexp de "grep" et les globs de "find"...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    echo * | grep 'un.*truc'
    find dir -name 'un*truc'
    car, la plupart du temps, on obtient le même résultat que sans les apostrophes... mais pas toujours:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    echo * | grep un.*truc
    find dir -name un*truc
    à cause d'expansions non maîtrisées, par exemple si le répertoire courant contient un fichier "un.truc".

    Évidemment, on peut/doit mettre des guillemets si la chaîne contient des variables à expanser.

  5. #5
    Membre éclairé
    Inscrit en
    Décembre 2010
    Messages
    258
    Détails du profil
    Informations forums :
    Inscription : Décembre 2010
    Messages : 258
    Par défaut
    Merci pour vos retours,
    Du coup la regex n'est peut être pas approprié pour ce que je veux faire...

    J'aimerai pouvoir utiliser le caractères *, par exemple :

    Fichier d'origine :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    dvdsid04
    dvdsid05
    dv20b01
    db20b02
    dvbdd01
    dvbdd02
    J'aimerai les résultats suivants :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ./my_script.sh ^dvd*
    dvdsid04
    dvdsid05

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ./my_script.sh *bdd*
    dvbdd01
    dvbdd02
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ./my_script.sh 01$
    dv20b01
    dvbdd01

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ./my_script.sh 20 (OU ./my_script.sh *20*)
    dv20b01
    db20b02

  6. #6
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 287
    Par défaut
    Bonjour

    Si tu continues ton dialogue de sourd, tu ne vas pas progresser.
    J'en remets une 4ème couche :

    Tu confonds les caractères joker et les expressions rationnelles (=regex) !

    • L'interpréteur de commande interprète * et ? comme des caractères joker.
    • Les expressions rationnelles/expressions régulières/regular expressions/regex utilisent * ? comme des quantificateurs. (de l'entité placée juste à gauche)

    Si tu souhaites utiliser des caractères joker dans le cadre d'une regex, cela ne va pas être possible. C'est l'un ou l'autre.
    Ou alors, tu utilises l'occasion de ton script pour trafiquer la formule d'entrée pour transformer '*' en '.*' ,ce qui semble douteux .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ filtre='*le*'
    $ filtre="${filtre//\*/.\*}"
    $ echo "$filtre"
    .*le.*
    Attention ! Les protections, par simple quotes, ou double quotes, sont, dans ton cas, à vérifier avec minutie.

  7. #7
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    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 102
    Par défaut
    Citation Envoyé par lokomass Voir le message
    Merci pour vos retours,
    Du coup la regex n'est peut être pas approprié pour ce que je veux faire...

    J'aimerai pouvoir utiliser le caractères *, par exemple :
    Tout à fait d'accord avec Flodelarab

    Pour clarifier un peu plus, il faudrait que tu comprennes bien la différence.

    Soit tu utilises des regexps, soit tu utilises des globs, soit tu inventes un nouveau langage qui va générer probablement une regexp (comme proposé: remplacer "*" par ".*").

    Les notations "^" et "$" font partie des regexps.
    La notation ".*" fait partie des regexps.

    La notation "*" fait partie des globs.

    Pour moi, le plus puissant serait d'utiliser les regexps (de base ou générées).


    Ensuite, il faut choisir s'il y a un implicite "^" et "$" ou pas.

    Du coup, avec implicite "^" et "$" (c'est-à-dire que le script les ajoute à la regexp passée en argument (et éventuellement remplace "*" par ".*")):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ./my_script.sh 'dvd.*' # commence par "dvd"
    dvdsid04
    dvdsid05
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ./my_script.sh '.*bdd.*' # contient "bdd"
    dvbdd01
    dvbdd02
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ./my_script.sh '.*01' # finit par "01"
    dv20b01
    dvbdd01
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ./my_script.sh '.*20.*' # contient "20"
    dv20b01
    db20b02
    Sans implicite "^" et "$" (c'est-à-dire que l'utilisateur doit les mettre s'il les veut):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ./my_script.sh '^dvd' # commence par "dvd"
    dvdsid04
    dvdsid05
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ./my_script.sh 'bdd' # contient "bdd"
    dvbdd01
    dvbdd02
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ./my_script.sh '01$' # finit par "01"
    dv20b01
    dvbdd01
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ./my_script.sh '20' # contient "20"
    dv20b01
    db20b02

  8. #8
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    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 102
    Par défaut
    Citation Envoyé par Flodelarab Voir le message
    Ou alors, tu utilises l'occasion de ton script pour trafiquer la formule d'entrée pour transformer '*' en '.*' ,ce qui semble douteux .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ filtre='*le*'
    $ filtre="${filtre//\*/.\*}"
    $ echo "$filtre"
    .*le.*
    Hum... C'est bizarre...

    Chez moi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ filtre='*le*'
    $ filtre2="${filtre//\*/.\*}"
    $ echo "$filtre2"
    .\*le.\*
    $ filtre3="${filtre//\*/.*}"
    $ echo "$filtre3"
    .*le.*
    $ echo $BASH_VERSION
    3.2.57(1)-release

  9. #9
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 287
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ filtre='*le*';filtre="${filtre//*/.*}";echo "$filtre"
    .*
    $ filtre='*le*';filtre="${filtre//\*/.*}";echo "$filtre"                                                                                                                                                                                                        
    .*le.*
    $ filtre='*le*';filtre="${filtre//\*/.\*}";echo "$filtre"                                                                                                                                                                                                       
    .*le.*
    $ filtre='*le*';filtre="${filtre//\*/.\\*}";echo "$filtre"                                                                                                                                                                                                      
    .\*le.\*
    $ filtre='*le*';filtre=${filtre//\*/.\*};echo "$filtre"
    .*le.*
    $ filtre='*le*';filtre=${filtre//\*/.*};echo "$filtre"
    .*le.*
    $ echo $BASH_VERSION
    4.4.12(1)-release

  10. #10
    Expert confirmé Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 041
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 041
    Par défaut
    salut,

    le globbing ne fonctionne que sur le système de fichiers et c'est bash qui s'en charge, là il ne s'agit pas de fichiers mais de chaines de caractères dans un fichier

    si on tape ./script dv* et que dans le répertoire on a un fichier dvcoincoin on se fait avoir par le globbing, pour éviter ça soit on prend l'habitude de mettre des guillemets simples autour du filtre systématiquement (./script 'dv*'), soit on récupère le filtre en interactif et pas en argument

    un truc comme ça fonctionne à priori :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #!/bin/bash
    read -p "--> filtre: " filter    # on echappe au globbing automatique de bash
    newfilter=${filter//\?/.?}       # on remplace '?' par '.?'
    newfilter=${newfilter//\*/.*?}   # on remplace '*' par '.*?' (non-greedy)
    echo "--> \"$filter\" transformé en \"$newfilter\""
    grep -P "$newfilter" fichier
    comme dit plus haut c'est un peu douteux, voire franchement cracra, mais ça fait le job comme attendu :
    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
    $ ./script.bash
    --> filtre: ^dvd*
    --> "^dvd*" transformé en "^dvd.*?"
    dvdsid04
    dvdsid05
     
    $ ./script.bash
    --> filtre: *bdd*
    --> "*bdd*" transformé en ".*?bdd.*?"
    dvbdd01
    dvbdd02
     
    $ ./script.bash
    --> filtre: 01$
    --> "01$" transformé en "01$"
    dv20b01
    dvbdd01
     
    $ ./script.bash
    --> filtre: 20
    --> "20" transformé en "20"
    dv20b01
    db20b02
     
    $ ./script.bash
    --> filtre: *20*
    --> "*20*" transformé en ".*?20.*?"
    dv20b01
    db20b02

  11. #11
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    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 102
    Par défaut
    Citation Envoyé par BufferBob Voir le message
    le globbing ne fonctionne que sur le système de fichiers et c'est bash qui s'en charge, là il ne s'agit pas de fichiers mais de chaines de caractères dans un fichier
    Au temps pour moi!
    Ça ne va pas être facile d'utiliser le globbing dans ce cas (à moins de créer des fichiers temporaires dehors dans un coin )

    si on tape ./script dv* et que dans le répertoire on a un fichier dvcoincoin on se fait avoir par le globbing, pour éviter ça soit on prend l'habitude de mettre des guillemets simples autour du filtre systématiquement (./script 'dv*'), soit on récupère le filtre en interactif et pas en argument
    un truc comme ça fonctionne à priori :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #!/bin/bash
    read -p "--> filtre: " filter    # on echappe au globbing automatique de bash
    newfilter=${filter//\?/.?}       # on remplace '?' par '.?'
    newfilter=${newfilter//\*/.*?}   # on remplace '*' par '.*?' (non-greedy)
    echo "--> \"$filter\" transformé en \"$newfilter\""
    grep -P "$newfilter" fichier
    comme dit plus haut c'est un peu douteux, voire franchement cracra, mais ça fait le job comme attendu
    Plutôt que "cracra", je dirais que c'est juste un nouveau langage, avec une syntaxe à mi-chemin entre glob et regexp, où certains caractères ont un sens spécial:
    - "^" pour début de ligne,
    - "$" pour fin de ligne,
    - "?" pour un caractère quelconque
    - "*" pour une chaine quelconque.

    Ça veut dire que pour un usage personnel, c'est bon, mais pour un usage partagé, ce nouveau langage doit être bien documenté.

    De plus, il doit être bien spécifié...

    [EDIT] (suite à la très juste remarque de Flodelarab):
    Rq: que se passe-t-il si on passe 'dv[0-9]*b01'? Il y a peu de chances que le script proposé trouve "dv20b01"...

    Rq: que se passe-t-il si on passe 'dv[0-9]*b01'? Il y a de fortes chances que le script proposé trouve "dv2oops0b01"...

    Rq: Peut-être faudrait-il ajouter à ton code newfilter=${newfilter//\./[.]} pour redonner au point "." son statut de caractère normal et éviter que "dvd*.txt" ne matche "dvd3txt" par exemple.

    Rq: de manière plus générale, peut-être faudrait-il quoter tous les caractères à l'exception de "^" "$" et faire le traitement spécial pour "?" et "*" afin de traiter les caractères spéciaux d'une regexp (comme "[" "]" "(" ")" etc.), pour que "^dvd[3]" trouve "dvd[3].jpeg" ou afin d'éviter des erreurs sur une saisie comme "^dvd[".

    [EDIT] Finalement beaucoup de boulot pour un résultat incertain...

  12. #12
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 287
    Par défaut
    Rq: que se passe-t-il si on passe 'dv[0-9]*b01'? Il y a peu de chances que le script proposé trouve "dv20b01"...
    Ben si. Le crochet trouve le 2, et l'étoile le 0.


    Mais arrêtez de vous prendre la tête. Je ne vois pas pour quelle obscure raison il réinventerait la roue. Qu'il apprenne les regex, comme tout le monde. Fin.

  13. #13
    Expert confirmé Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 041
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 041
    Par défaut
    Citation Envoyé par jack-ft Voir le message
    Plutôt que "cracra", je dirais que c'est juste un nouveau langage, (...) ce nouveau langage doit être bien documenté.
    (...)
    Rq: que se passe-t-il si on passe 'dv[0-9]*b01'? Il y a peu de chances que le script proposé trouve "dv20b01"...
    ben c'est justement en ça que je disais que c'est cracra en fait, on ne peut pas utiliser le globbing sur des chaines arbitraires du coup pour satisfaire à la demande du PO on est rendu à s'interfacer entre la syntaxe des regexp et le pseudo-globbing tapé par l'utilisateur.

    là je donne un exemple qui tient en 5 lignes, c'est forcément "cracra", la grammaire n'est pas du tout maitrisée (et tu en donnes un exemple parmi pleins d'autres), s'il était question de faire un "nouveau langage" je pense que j'aurais recours à un vrai parser en définissant la grammaire exacte pour ensuite faire la transcription en regex classique (et accessoirement je coderai pas ça en bash).

    là on s'en sort avec une astuce, une substitution ou deux, faut plutôt voir ça comme une solution du pauvre qui se contente de satisfaire des consignes permissives/pas assez strictes

    Citation Envoyé par Flodelarab Voir le message
    Ben si. Le crochet trouve le 2, et l'étoile le 0.
    bien vu bon le fait est que jack-ft n'a évidemment pas tort, dv[0-9]*b01 va du coup aussi matcher "dv20_pouet_b01"

    Citation Envoyé par Flodelarab Voir le message
    Je ne vois pas pour quelle obscure raison il réinventerait la roue.
    bof.. ils sont pleins à l'avoir fait, à commencer par les langages de programmation eux-même, y'en a pas deux qui partagent le même moteur d'expressions rationnelles, du coup "ça ressemble... mais c'est pas pareil"

    c'est pas un choix que je ferais non plus, et les regex c'est clairement un indispensable quand on programme un tant soit peu, mais qu'on veuille réinventer la roue à l'occasion pour des raisons farfelues ça ne me choque pas (plus?) outre mesure

Discussions similaires

  1. Arguments pour et contre Access ?
    Par bottura dans le forum Sondages et Débats
    Réponses: 240
    Dernier message: 23/03/2018, 23h25
  2. Passer une REGEX en argument de fonction puis en attribut
    Par helkøwsky dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 04/06/2013, 22h40
  3. Récuperer Arguments sur la ligne de commande ?
    Par Muetdhiver dans le forum x86 16-bits
    Réponses: 9
    Dernier message: 20/01/2003, 21h01
  4. fonction renvoyant un tableau en argument
    Par Jones dans le forum Langage
    Réponses: 6
    Dernier message: 30/09/2002, 18h20
  5. Procédure avec un nombre variable d'arguments
    Par charly dans le forum Langage
    Réponses: 15
    Dernier message: 21/06/2002, 11h08

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