GREP nombre impair

eZula Messages postés 3509 Statut Contributeur -  
eZula Messages postés 3509 Statut Contributeur -
Salut,

Pour déboguer un batch DOS, je cherche à matcher des lignes foireuses, par exemple celles qui pourraient contenir un guillemet suivi de n'importe quelle expression sauf un guillemet. Aucun de mes essais n'a abouti à qque chose de valable.
Finalement, encore plus intéressant, j'ai pensé plutôt à matcher ttes les lignes d'un fichier qui contiennent un nombre impair de guillemets

"coucou"
cou"cou
cou""cou
coucou"
"couco"u"


donc ici lignes 2, 4 et 5. Y a-t-il, avec l'option -c par exemple une solution à ce problème sans passer par aucune autre commande Linux (en dehors de SED à la rigueur) ?
Ce serait bien aussi de caser l'option -n pour avoir l'affichage des lignes et de leurs numéros

Je suis également intéressé par une regexp correspondant au premier essai (simple curiosité)

Merci
Configuration: Windows XP
Firefox 3.0.8

43 réponses

  • 1
  • 2
  • 3
Résumé de la discussion

La problématique consiste à détecter dans un fichier les lignes contenant un nombre impair de guillemets, dans le cadre du débogage d'un batch DOS, en privilégiant sed ou awk. Plusieurs réponses privilégient awk pour compter les guillemets et restituer les lignes dont le compte est impair, en utilisant gsub et une condition modulo. Des variantes existent, comme traiter les lignes contenant des guillemets et déterminer la parité via gsub, ou combiner sed et substitution pour évaluer la présence et l'absence des guillemets. En pratique, certains exemples affichent le numéro de ligne et son contenu lorsque le comptage est impair, tout en signalant que l'échappement des guillemets sur Windows peut compliquer l'analyse.

Bobot (l'IA à votre service)
  1. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 944
     
    Pourquoi ne pas simplement installer cygwin ?
    1
  2. dubcek Messages postés 18627 Date d'inscription   Statut Contributeur Dernière intervention   5 660
     
    hello
    parce que le echo ne s'exécute qu'une fois et après la dernière ligne, il faut plutôt utiliser sed ou awk
    1
  3. jipicy Messages postés 40842 Date d'inscription   Statut Modérateur Dernière intervention   4 898
     
    Salut,

    J'ai torturé 'grep" dans tous les sens, mais je n'ai rien pu en tirer ;-(((

    Une solution avec "sed" :
    [tmpfs]$ cat -n plop
         1  "coucou"
         2  cou"cou
         3  cou""cou
         4  coucou"
         5  "cou"cou"
         6  "cou"c"o"u
    
    [tmpfs]$ cat -n plop | sed -n 'h;:z;/"/{s/\("[^"]*"\)//1;tz;g;p}'
         2  cou"cou
         4  coucou"
         5  "cou"cou"
    
    [tmpfs]$
    Si tu ne veux pas du "cat -n" remplace-le par :
    sed = plop | sed 'N;s/\n/ - /' |
    ;-))
    0
  4. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 944
     
    Faisable avec sed. Le cut ne sert qu'à extraire le numéro de ligne.
    (mando@aldur) (~) $ cat plop.txt
    "coucou"
    cou"cou
    cou""cou
    coucou"
    "couco"u"
    
    (mando@aldur) (~) $ cat plop.txt | sed -e s/\"[^\"]*\"//g | grep -n "\"" | cut -f1 -d:
    2
    4
    5
    

    Bonne chance
    0
    1. jipicy Messages postés 40842 Date d'inscription   Statut Modérateur Dernière intervention   4 898
       
      Chapeau bas Miss (comme dirait lami20j) ;-))
      0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 944
     
    Merci :-) Mais bon le sed modifie la ligne. Mon approche consiste à virer les "xxx". Du coup si le nombre de guillemets est impair, il en reste un après le sed et le dernier grep extrait la ligne (modifiée donc).

    Bref c'est pas complètement parfait, car je ne vois pas comment avoir simplement le numéro de ligne + la ligne complète sans passer par un script (il faudrait stocker la ligne lue et la réécrire si la ligne matche).
    0
  7. eZula Messages postés 3509 Statut Contributeur 392
     
    Merci :)

    le malheur dans tout ça c'est que c'est sous windows comme d'habitude, c'est pour cela que j'ai précisé "sans autre commande Linux, j'ai juste sed, grep et uniq). La seule approche à peu près ressemblante que je vois c'est

    for /f "tokens=*" %%A IN (Path.txt) DO ECHO %%A | sed -e "s/\"[^\"]*\"//g" | grep -n "\""


    voilà l'interprétation :

    >for /F "tokens=*" %A IN (Path.txt) DO ECHO %A   | sed -e "s/\"[\"]*\"//g" | grep -n "\""
    
    >ECHO "coucou"   | sed -e "s/\"[\"]*\"//g" | grep -n "\""
    sed: can't read |: Invalid argument
    sed: can't read grep: No such file or directory
    sed: can't read ": Invalid argument
    Le processus a tenté d'écrire sur un canal inexistant.
    
    >ECHO cou"cou   | sed -e "s/\"[\"]*\"//g" | grep -n "\""
    sed: can't read |: Invalid argument
    sed: can't read grep: No such file or directory
    sed: can't read ": Invalid argument
    Le processus a tenté d'écrire sur un canal inexistant.
    
    >ECHO cou""cou   | sed -e "s/\"[\"]*\"//g" | grep -n "\""
    sed: can't read |: Invalid argument
    sed: can't read grep: No such file or directory
    sed: can't read ": Invalid argument
    Le processus a tenté d'écrire sur un canal inexistant.
    
    >ECHO coucou"   | sed -e "s/\"[\"]*\"//g" | grep -n "\""
    sed: can't read |: Invalid argument
    sed: can't read grep: No such file or directory
    sed: can't read ": Invalid argument
    Le processus a tenté d'écrire sur un canal inexistant.
    
    >ECHO "couco"u"   | sed -e "s/\"[\"]*\"//g" | grep -n "\""
    sed: can't read |: Invalid argument
    sed: can't read grep: No such file or directory
    sed: can't read ": Invalid argument
    Le processus a tenté d'écrire sur un canal inexistant.
    
    >ECHO ~%%i   | sed -e "s/\"[\"]*\"//g" | grep -n "\""
    sed: can't read |: Invalid argument
    sed: can't read grep: No such file or directory
    sed: can't read ": Invalid argument
    Le processus a tenté d'écrire sur un canal inexistant.


    j'utilise ce sed http://gnuwin32.sourceforge.net/packages/sed.htm 4.1.5

    Le fait d'écrire un script après comme suggéré ne serait pas contraignant, le vrai souci c'est d'arriver à encadrer ce motif qui parait tout simple :)
    0
  8. jipicy Messages postés 40842 Date d'inscription   Statut Modérateur Dernière intervention   4 898
     
    Ma solution au post #1 ne va pas ?
    0
  9. eZula Messages postés 3509 Statut Contributeur 392
     
    j'ai bidouillé ta commande comme ceci :

    >grep -n "." Path.txt | sed -n "h;:z;/\"/{s/\(\"[^\"]*\"\)//1;tz;g;p}"
    2:cou"cou
    4:coucou"
    5:"couco"u"

    merde, ça a l'air bon ? :))
    0
  10. eZula Messages postés 3509 Statut Contributeur 392
     
    Excuse, mais tu pourrais expliciter cette expression régulière sed, s'il te plait ?

    Merci
    0
  11. jipicy Messages postés 40842 Date d'inscription   Statut Modérateur Dernière intervention   4 898
     
    #n                      # Affichage sur demande
    h                       # On stocke la ligne dans la mémoire annexe
    :z                      # Étiquette
    /"/ {                   # Si on trouve un guillemet 
        s/\("[^"]*"\)//1    # On essaie de substituer tout ce qui se
                            # trouve entre 2 guillemets par rien
        t z                 # Si une substitution a eu lieu on se branche
                            # à l'étiquette et on remet ça
        g                   # Sinon (qu'un guillemet restant) on remet
                            # la ligne stockée dans la mémoire secondaire
                            # dans l'espace de travail
        p                   # Et on l'imprime
    }
    0
  12. eZula Messages postés 3509 Statut Contributeur 392
     
    Super, merci encore ;)

    j'applique ton modèle à d'autres problèmes possibles, et je rencontre une autre difficulté, pour une situation quasi-identique : nombre impair de % (exemple de ligne : utryu%uio)

    grep -n "." Path.txt | sed -n "h;:z;/%/{s/\(%[^%]*%\)//1;tz;g;p}"


    ça ne fonctionne pas, même en protégeant le % avec un antislash, tu aurais une idée ? car comme précisé avec d'autres caractères recherchés, tel que le ^, et une fois protégé,

    >grep -n "." Path.txt   | sed -n "h;:z;/\^/{s/\(\^[^\^]*\^\)//1;tz;g;p}"
    8:cou^cou


    le motif est bien trouvé.
    0
  13. jipicy Messages postés 40842 Date d'inscription   Statut Modérateur Dernière intervention   4 898
     
    [tmpfs]$ cat plop
    %coucou%
    cou%cou
    cou%%cou
    coucou%
    %cou%cou%
    %cou%c%o%u
    
    [tmpfs]$ cat -n plop | sed -n 'h;:z;/%/{s/\(%[^%]*%\)//1;tz;g;p}'
         2  cou%cou
         4  coucou%
         5  %cou%cou%
    
    [tmpfs]$
    Chez moi ça marche, par contre comme "%" est un caractère réservé de Windows (au même titre que "!" pour GNU/Linux), il est fort possible que ça interfère...

    Désolé ;-(
    0
  14. eZula Messages postés 3509 Statut Contributeur 392
     
    en effet, le caractère ne s'affiche même pas dans le terminal :)

    comment tu fais sous Linux pour protéger un caractère réservé ?
    0
    1. jipicy Messages postés 40842 Date d'inscription   Statut Modérateur Dernière intervention   4 898
       
      Normalement en le protégeant avec un anti-slash '\!", par contre j'ai remarqué que tu utilisais des doubles quotes autour de ton expression, essaie avec des quotes simples...

      En bash ça a son importance ;-\
      0
  15. eZula Messages postés 3509 Statut Contributeur 392
     
    Sous windows je crois que les ' ' ne marchent pas

    grep -n '.' Path.txt   | sed -n 'h;:z;/\"/{s/\(\"[\"]*\"\)//1;tz;g;p}'
    sed: -e expression #1, char 1: unknown command: `''


    Sans par contre c'est possible, parfois

    grep -n . Path.txt   | sed -n h;:z;/\"/{s/\(\"[\"]*\"\)//1;tz;g;p}
    1:"coucou"
    2:cou"cou
    4:coucou"
    5:"couco"u"


    Pour en revenir à la recherche du motif "% impair" pas trouvé de solutions, guillemets ou pas, et même en faisant passer ce caractère dans une variable rien à faire, il ne s'affiche pas

    grep -n . Path.txt   | sed -n h;:z;/\[\\)//1;tz;g;p}
    sed: -e expression #1, char 13: unknown command: `/'
    grep: write error: Invalid argument


    quoique...

    grep "%" Path.txt
    utryu%uio


    je vais voir peut être avec findstr...
    0
  16. jipicy Messages postés 40842 Date d'inscription   Statut Modérateur Dernière intervention   4 898
     
    grep -n '.' Path.txt | sed -n 'h;:z;/\"/{s/\(\"[\"]*\"\)//1;tz;g;p}'
    sed: -e expression #1, char 1: unknown command: `''


    A ce moment là il ne faut pas échapper les \", essaye sans les échapper...
    0
  17. eZula Messages postés 3509 Statut Contributeur 392
     
    j'avais essayé comme ceci

    grep -n "." Path.txt | sed -n "h;:z;/%/{s/\(%[%]*%\)//1;tz;g;p}"


    et dans le shell les caractères % ne s'affichent pas d'où erreur
    0
  18. jipicy Messages postés 40842 Date d'inscription   Statut Modérateur Dernière intervention   4 898
     
    Essaie comme ça :
    grep -n "." Path.txt | sed -n 'h;:z;/%/{s/\(%[%]*%\)//1;tz;g;p}'
    0
  19. eZula Messages postés 3509 Statut Contributeur 392
     
    >grep -n "." Path.txt | sed -n 'h;:z;/[\)//1;tz;g;p}'
    sed: -e expression #1, char 1: unknown command: `''
    grep: write error: Invalid argument


    Edit >

    >grep -n "." Path.txt | sed -n "h;:z;/[\)//1;tz;g;p}"
    sed: -e expression #1, char 20: unterminated address regex


    bouh :/

    ça doit vraiment être ce caractère %, s'il y en a deux il doit supposer que ce qui se situe entre est une variable, et vu que ce n'est pas déclaré parcequ'elle n'existe pas, ça ne fonctionne pas.

    Cet exemple avec les & marche, sans protection...

    >grep -n "." Path.txt | sed -n "h;:z;/&/{s/\(&[&]*&\)//1;tz;g;p}"
    8:regrg&gedr


    faudrait l'empêcher d'interpréter le % c'est pas gagné. Avec d'autres séparateurs pour SED tu crois que c'est possible ?
    0
    1. jipicy Messages postés 40842 Date d'inscription   Statut Modérateur Dernière intervention   4 898
       
      Effectivement c'est l'interprétation de % par Windows qui pose problème, va te falloir attendre un expert en Windows ;-))

      Quant au séparateur, ça n'a rien à voir dans la mesure où le caractère "%" n'est pas utilisé comme séparateur.
      On en change quand justement il risque d'y avoir confusion et pour éviter la protection comme dans un chemin :
      sed 's/\/home\/user\/chemin/blablabla/'
      
      sed 's%/home/user/chemin%blablabla%'

      là oui c'est utile, ne serait-ce que pour la visibilité ;-))
      0
  20. dubcek Messages postés 18627 Date d'inscription   Statut Contributeur Dernière intervention   5 660
     
    hello
    et avec awk, disponible
    awk ' /\"/ {x=$0;n=gsub("\"", "X", x);if(n % 2 ) print NR, $0 }' 
    0
  21. eZula Messages postés 3509 Statut Contributeur 392
     
    Salut,

    donc avec awk.exe, $ComptFlop=3 :)

    >awk " /\"/ {x=$0;n=gsub("\"", "X", x);if(n % 2 ) print NR, $0}"
    awk:  /"/ {x=$0;n=gsub(", X, x);if(n % 2 ) print NR, $0 }
    awk:                   ^ unterminated string
    
    >awk " /\"/ {x=$0;n=gsub("\"", "X", x);if(n % 2 ) print NR, $0}" resultat.txt
    awk:  /"/ {x=$0;n=gsub(", X, x);if(n % 2 ) print NR, $0 }
    awk:                   ^ unterminated string
    
    >type resultat.txt | awk " /\"/ {x=$0;n=gsub("\"", "X", x);if(n % 2 ) print NR, $0 }"
    awk:  /"/ {x=$0;n=gsub(", X, x);if(n % 2 ) print NR, $0 }
    awk:                   ^ unterminated string
    Le processus a tenté d'écrire sur un canal inexistant.


    j'ai manqué un truc ?
    0
  • 1
  • 2
  • 3