Forum Programmation.shell [sed] Effacer les lignes d'un fichier [Résolu]

Posté par .
Tags : aucun
0
7
juin
2011

Bonjour,
dans une liste de mots contenant des anagrammes, j'essaie de supprimer, avec SED, les lignes contenant des espaces. Voici un extrait du fichier pour le mot "repos":

poser
prose
repos
pose r.
posée r.
posée ré
etc.

Les trois derniers ne m'intéressent pas (cépadufran C). Et ce ne sont pas non plus des anagrammes valides de mon point de vue.

Problème : je dois mal me débrouiller avec SED. Je fais

sed s/[a-z]\s[a-z]//g < monfichier > fichiertrie

J'ai aussi essayé avec le pattern
^[a-z]*\s[a-z]*

puis je me suis rendu compte que de toute façon, cela supprimerait l'espace mais pas la ligne... Mais notons que je n'arrivais pas à supprimer les espaces avec ce code.

J'ai alors essayé

sed '/[a-z]*\s[a-z]*/d'

mais ça ne marche pas, que j'indique ou non le début et fin de ligne (^$).

Je croyais savoir faire ça, mais non. Je n'ai pas envie de relire toute la doc de sed, please, help me ! !
Merci

  • # Tout simplement

    Posté par . Évalué à 2.

    sed '/^.* .*$/d'
    

    Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

    • [^] # Re: Tout simplement

      Posté par . Évalué à 5.

      Sinon plus simple en grep :

      grep -v ' '
      

      Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

    • [^] # Re: Tout simplement

      Posté par . Évalué à 1.

      Merci beaucoup de ta réponse,

      mais avec ce code, toutes les lignes mon fichier sont effacées...
      Peut être faudrait-il que je vérifie qu'il s'agit bien d'espaces et non d'autre chose. Comment faire ?

      Merci

      • [^] # od -c

        Posté par . Évalué à 1.

        Peut être faudrait-il que je vérifie qu'il s'agit bien d'espaces et non d'autre chose. Comment faire ?

        od -c list.txt
        

        l'option -c permettant l'affichage des caractères ascii, \n, \t etc

        • [^] # Re: od -c

          Posté par . Évalué à 0.

          Je viens de lancer la commande pour un fichier ou je n'ai laissé que :
          >pose r.
          un des mots proposé comme anagramme de 'repos' par an

          ça donne :
          > 0000000 p o s e r . n
          > 0000010

          On voit le retour à la ligne n mais pour le reste.... Une idée ?

          • [^] # Re: od -c

            Posté par . Évalué à 1.

            L'idée c'est de voir si dans tes lignes que tu considère comme valides, il n'y ai pas un espaceen fin de ligne avant le \n (ce qui doit être probables vu qu'un espace apparait entre deux lettres dans certains de tes anagrammes.

            Dass ce cas, od -c, qui sépare chaque caractère avec deux espaces (si je ne me trompe pas), devrait t'afficher une suite de 5 espaces avant le \n.

    • [^] # Re: Tout simplement

      Posté par . Évalué à 2.

      Ca serait peut-être bien d'expliquer le pourquoi de la ligne ( comme une sombre histoire d'apprendre qqn à pêcher plutot que de lui fournir le poisson).

      • [^] # Re: Tout simplement

        Posté par . Évalué à 3.

        Tu as raison j'ai étais un peu expéditif.

        La commande /d de sed supprime ce qui a était "matché" par l'expression. Donc si on veut supprimer une ligne il faut matcher toute la ligne. Dans le langage d'expression de sed (je ne sais pas si ça fait partie des expressions régulières basiques ou étendues ou PCRE), $ est la fin de ligne (comme dans ex ou vi) et ^ est le début de ligne (donc /^a$/ matche les lignes qui sont composées d'un unique a). Le . est le jocker (non il tue pas batman), il remplace n'importe quel caractère et * est un quantifieur qui signifie que l'expression avant peut être répétées 0, 1 ou plusieurs fois.

        Cette expression :

        /^.* .*$/
        

        signifie donc que je cherche toutes les lignes (grâce au ^ et au $) qui commencent éventuellement par une chaîne quelconque et finissent éventuellement par une chaîne quelconque, mais on forcément un espace (au milieu, au début ou à la fin de la ligne.

        Bref grep est carrément tout indiqué car il travail directement avec les lignes. Sont objectif est de filtrer.

        grep ' '
        

        garde toutes les lignes qui ont un espace et l'option -v inverse le résultat (ne garde que les lignes qui n'ont pas d'espace).

        Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

        • [^] # Re: Tout simplement

          Posté par . Évalué à 0.

          Je te remercie de ton aide,
          malheureusement :

          cat fichier.txt | grep -v ' ' > fichierOut.txt # fichier vide
          cat fichier | grep -v ' ' # ne montre rien à l'écran
          cat fichier | grep ' '    # montre tous les mots avec ou sans espace
          sed '/^.* .*$/d' < in > out  # produit un fichier vide
          

          Merci aussi de tes remarques sur SED, je connaissais mais mon incapacité à élaborer une commande simple me fait honte... J'ai le 'Sed & awk' O'reilly mais pas chez moi...

          Pourtant, j'ai réussi à écrire une commande qui efface les lignes avec des mots de plus de 5 lettres (je ne garde que les anagrammes strict de "repos"), hors espace :

          sed '/^[a-z][a-z][a-z][a-z][a-z][a-z][a-z]*$/d'
          

          qui supprime les lignes avec des mots de 6 caractères ou plus. Et ça marche... alors...

          Merci tout de même ! :)

          • [^] # Re: Tout simplement

            Posté par (page perso) . Évalué à 3.

            Tout d'abord UUOC#Useless_use_of_cat) !
            On ne fait pas :
            cat fichier.txt | grep -v ' '
            mais :
            grep -v ' ' fichier.txt
            Ensuite si cette commande ne te renvoie rien, c'est sans doute que tu as une espace à la fin de chaque ligne, tout simplement.
            Ceci devrait faire l'affaire en supprimant les lignes contenant une espace mais avec au moins un caractère derrière :
            grep -v -E ' [^ ]+$' fichier.txt

            It's a fez. I wear a fez now. Fezes are cool !

            • [^] # Re: Tout simplement

              Posté par . Évalué à 2.

              Celle-ci permet en outre de supprimer les lignes remplies d'espaces.

              sed '/^.* ..*$\|^  *$/d' fichier
              

              Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

        • [^] # Re: Tout simplement

          Posté par (page perso) . Évalué à 3.

          Sed aussi travaille sur les lignes, et “d” supprime la ligne. Avec une expression rationnelle pour sélectionner les lignes qui contiennent un espace, on a :

          sed '/ /d'
          

          Je ne dis pas que c’est mieux que grep, mais ce n’est pas méchant non plus.

          • [^] # Re: Tout simplement

            Posté par . Évalué à 2.

            Tu as raison c'est cette phrase qui m'a induit en erreur (et j'ai pas pris le temps de tester au boulot) :

            puis je me suis rendu compte que de toute façon, cela supprimerait l'espace mais pas la ligne …

            Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

  • # J'ai trouvé !

    Posté par . Évalué à 0.

    Ouf ! !
    J'ai enfin trouvé un truc qui marche !

    sed '/\w.* \w/d' < in > out
    

    Autrement dit, "effacer toute ligne qui contient au moins un mot suivi ou non d'un caractère quelconque, suivi d'une espace, suivi d'un mot". Yeah !

    Bah punaise, il était temps !
    Je suis inscrit à la mailng list Sed, mais ils parlent vraiment une autre langue je trouve. Je vais quand même leur soumettre le problème de nos tentatives qui ne marchaient pas.

    Merci à vous ! Bonne soirée !

    • [^] # Re: J'ai trouvé !

      Posté par . Évalué à 1.

      sed sait travailler avec des fichiers tu n'es pas obligé de passer par un pipe :

      sed '/.../d' in > out
      

      Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

      • [^] # Re: J'ai trouvé !

        Posté par . Évalué à 2.

        sed '/w.* w/d' < in > out

        Tu vois un pipe dans cette commande ?

        Sinon la solution la plus simple est celle fournie par jyes un peu plus haut:

        sed '/ /d' < in > out
        
        • [^] # Re: J'ai trouvé !

          Posté par . Évalué à 1.

          Un via le caractère < et un via le caractère >. Les redirections utilisent des pipes. C'est la seule technique sous Unix pour arriver à faire des redirection de flux.

          Donc oui sed 'machin' < in c'est montrer qu'on a pas lu le man et c'est une mauvaise utilisation de la redirection au même titre que les UUOC.

          Au cas où l'option -i peut être utile dans ce genre de cas pour gérer la sortie.

          Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

          • [^] # Re: J'ai trouvé !

            Posté par . Évalué à 3.

            Un via le caractère < et un via le caractère >. Les redirections utilisent des pipes. C'est la seule technique sous Unix pour arriver à faire des redirection de flux.

            Il va falloir que tu revoies tes bases de programmation système.
            La gestion de la redirection se fait en réassignant les descripteurs de fichier 0 et 1 avant de lancer la commande. De mémoire, ça ressemble à ça en C:

            if ((pid = fork()) == 0) {
              close(0);
              open("in", O_RDONLY);
              close(1);
              open("out", O_WRONLY);
              execlp("sed",...);
            }
            

            Pas de pipe la dedans.

            • [^] # Re: J'ai trouvé !

              Posté par . Évalué à 2.

              Tu as raison (même s'il vaut mieux utiliser des noms logiques). Excuse moi, ça fait effectivement trop longtemps que je n'y ai pas touché. Il est tout de même dommage d'utiliser une redirection là où le logiciel peut s'en passer.

              Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

        • [^] # Re: J'ai trouvé !

          Posté par . Évalué à -1.

          sed '/ /d' < in > out
          

          Cette commande produit un fichier vide. Mais merci quand même à vous de ces suggestions, je garde ma solution car... elle marche, même si elle n'est pas très élégante.
          • [^] # Re: J'ai trouvé !

            Posté par . Évalué à 2.

            Tu es sûr ?
            Je suis tellement surpris que je viens de vérifier:

            $ cat > in
            poser
            prose
            repos
            pose r.
            posée r.
            posée ré
            ^D
            $ sed '/ /d' < in
            poser
            prose
            repos
            

            chezmoiçamarche :(

            • [^] # Re: J'ai trouvé !

              Posté par (page perso) . Évalué à 1.

              Ça marche chez toi mais il a manifestement une espace à la fin de chaque ligne ('toto ') et toi pas. D'où plus rien à la sortie.

              It's a fez. I wear a fez now. Fezes are cool !

              • [^] # Re: J'ai trouvé !

                Posté par . Évalué à 4.

                Ma solution correspond à la question que tu as posé: «Bonjour,
                dans une liste de mots contenant des anagrammes, j'essaie de supprimer, avec SED, les lignes contenant des espaces.»

                Pour ne pas supprimer les lignes ayant un espace uniquement en fin de ligne, la solution reste plus simple que celle que tu proposes:

                sed '/ ./d' < in > out
                
      • [^] # Re: J'ai trouvé !

        Posté par (page perso) . Évalué à 0.

        Dans ce cas là :
        sed -i.bak '/.../d' in
        le -i remplace directement le fichier et si on ajoute le .bak, il fera lui même la sauvegarde.

  • # Perl

    Posté par . Évalué à 3.

    Mieux que le shell, mieux que le sed : le Perl (oui je suis fan)

    perl -ne 'print if ! /\s/' fichier.txt > fichier2.txt

    ou sinon supprimer tout ce qui se trouve après l'espace :

    perl -pe 's/\s.*$//' fichier.txt > fichier2.txt

    et avec l'édition en ligne :

    perl -i -pe 's/\s.*$//' fichier.txt

  • # Essai ...

    Posté par (page perso) . Évalué à 1.

    Est-ce le comportement recherché ?

    bigbob@bigbob-laptop:~$ cat > in
    poser
    prose
    repos
    pose r.
    posée r.
    posée ré
    bigbob@bigbob-laptop:~$ grep -v '[:space:](http://fr.wikipedia.org/wiki/:space: "Définition Wikipédia")' in
    poser
    prose
    repos
    bigbob@bigbob-laptop:~$
    

    A++

  • # Et en évitant sed, awk, grep et compagnie

    Posté par (page perso) . Évalué à 0.

    # Bash 4 minimum
    #
    #
    # 
    while read a; do
      if [ "${a//[[:space:]]//}" = "${a}" ]; then
        echo "${a}" >> out
      fi
    done < in
    

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.