Script shell bash sur un texte

j'ai un exo qui consiste à insérer une ligne en premier argument($1)
cette ligne doit se situer au milieu d'un texte déjà constitué d'un fichier existant , par exemple :

ligne 1
ligne2
nouvelle ligne
ligne 3
ligne4

on doit le faire sans utiliser les commandes sed et awk , en calculant les lignes ; j'ai fait comme ceci mais ça plante

lignes= wc -l $2 | cut -c1

milieu= $(($lignes/ 2))

si vous avez des idées , merci
Configuration: Windows XP
Firefox 1.5.0.11

54 réponses

Résumé de la discussion

L’objectif consiste à insérer une ligne fournie en premier argument dans le milieu d’un fichier texte existant, sans recourir à sed ni awk, en calculant dynamiquement le point médian. La solution consiste à calculer le milieu à partir du nombre de lignes, puis à assembler le fichier avec head et tail autour de la ligne fournie, insérée entre les deux parties. Par exemple, on peut décrire le procédé comme le calcul du milieu puis la composition du fichier avec head et tail et l’insertion est effectuée via une redirection vers un fichier intermédiaire. En pratique, il peut être utile d’utiliser un fichier temporaire et de vérifier les permissions ou d’ajuster le calcul du milieu si le fichier est hybride (lignes vides, retours chariot).

Bobot (l’IA à votre service)
  1. Modérateur
    Salut,

    pourquoi pas
    root@debian:~# cat ccm.sh
    #!/bin/bash
    a=$(ls -l $1 | cut -d' ' -f1)
    b=${a//[rwx]/"\toui\t"}
    aa=${b//-/"\tnon\t"}
    user=$(ls -l $1 | cut -d ' ' -f3)
    groupe=$(ls -l $1 | cut -d ' ' -f4)
    u=${aa:7:21} g=${aa:21:21} o=${aa:42:21}
    echo -e "    \t\t\tread\t\twrite\t\texecute"
    echo -e "user $user\t$u\ngroupe $groupe\t$g\nautres\t\t$o"
    
    root@debian:~# sh ccm.sh ccm.sh
                            read            write           execute
    user root               oui             oui             non
    groupe lami20j          non             oui             non
    autres                  non             oui             non
    root@debian:~#
    
    1. Modérateur
      Salut,
      [jp@MDK tmpfs]$ cat niceLP.sh
      #! /bin/bash
      
      echo "$1" > tmp
      milieu=$(expr $(wc -l $2 | cut -d" " -f1) / 2)
      split -l "$milieu" bar.txt tmp
      cat tmpaa tmp tmpab > fichier
      rm -f tmp*
      
      [jp@MDK tmpfs]$ sh niceLP.sh "Ligne introduite" bar.txt
      
      [jp@MDK tmpfs]$ cat fichier
      Ligne 1
      Ligne 2
      Ligne 3
      Ligne 4
      Ligne 5
      Ligne 6
      Ligne introduite
      Ligne 7
      Ligne 8
      Ligne 9
      Ligne 10
      Ligne 11
      Ligne 12
      [jp@MDK tmpfs]$ 
      Voir le "man split".

      ;-))

      Édit : La soluce à "lami20j" (enfin dans l'esprit je pense) :
      #! /bin/bash
      
      milieu=$(expr $(wc -l $2 | cut -d" " -f1) / 2)
      head -"$milieu" "$2" > fichier
      echo "$1" >> fichier
      tail -"$milieu" "$2" >> fichier
      
      1. Modérateur
        Salut,

        Édit : La soluce à "lami20j" (enfin dans l'esprit je pense) :
        je confirme :-))
        Merci.
    2. oui on peut le faire avec les commandes tail et head , j'ai essayé mais ça ne marche pas , à chaque fois il me supprime les lignes du fichier ( fichier)
      pourtant j'ai bien mis les ">>" ; y a t il un pb avec le $milieu ?
      merci
      1. Modérateur
        Copie/Colle ton script, ton fichier de référence et ton fichier de sortie. Merci.
        1. voici le script
          ligneinsere

          #! /bin/bash

          centre=$(expr $(wc -l $2 | cut -d" " -f1) / 2)
          head -"$centre" "$2" > fichier
          echo "$1" >> fichier
          tail -"$centre" "$2" >> fichier

          execution :
          $ sh ligneinsere "ligne au milieu" fichier

          resultat
          ligne au milieu
          ligne au milieu
          1. Modérateur
            Juste un truc : j'ai l'impression que tu lances ton script sur le fichier même faisant office de fichier de sortie, non ?

            Il faut que le fichier où tu vas lire les lignes soit différent du fichier où tu vas écrire la sortie !!!

            Peut être ne suis-je pas dans l'exactitude de la chose, dans ce cas là, sorry ;-(
            1. ok tu as raison , désolé je prenais le meme fichier d'entrée et de sortie
              merci encore
              1. bonjour a tous j'ai le même problème mais je l'ai résolu autrement bon c'est sur c'est quand même plus facile...

                head -3 fichier > temp

                echo ligne de texte >> temp

                tail -3 fichier >> temp

                cat temp > fichier

                rm temp

                cat fichier

                j'ai essayé d'analyser la soluce au dessus mais je bloque avec les variables j'ai pas tout compris, wc -l ok, mais aprés..........................

                A+
                1. quand le nombre de ligne est pair, ca fonctionne par contre quand c'est impair, il efface une ligne.

                  pour faire un test en plus, je dois utiliser quoi ?
                  1. Salut,
                    à mon avis, vu que la nombre de ligne est impair, il le coupe bien en deux mais en deux partie inégale 91/2=45,5 ce qui donne 46/45, tu me suis?
                    Je t'ai trouvé ça, je pense que ça devrait te satisfaire, du moins je l'espère, sinon je peux te pondre un petit script qui peux te permettre de donné la valeur a head et a tail, bon c'est sur si ton fichier 351443134143142346 lignes, prévoit une calculette....

                    #! /bin/bash

                    centre1=$(expr $(wc -l $2 | cut -d" " -f1) / 2)
                    centre2=$(($centre1 +1))
                    head -"$centre" "$2" > fichier
                    echo "$1" >> fichier
                    tail -"$centre2" "$2" >> fichier

                    Dsl pour le double post jipicy, j'ai voulu l'éditer mais tu m'as devancés de quelque secondes..............

                    Merci pour eux ;)
                    1. Bonjour,

                      J'ai le même problème aussi. ta solution est intéressante, mais tu changes le nom du fichier; dans mon exo, on ne doit pas le changer !

                      Alors je dois encore chercher la solution. je vais voir comment je peux changer ton script.

                      Mais, bien sûr, si tu peux donner un coup de main, ça peut toujours accélérer les choses!

                      Merci
                      1. bonjour,

                        Ce que je voudrais, c'est avec un fichier yo :

                        eeeee
                        eeeee
                        eeeee
                        eeeee

                        Insérer au milieu : hello, en sautant une ligne ; cela devrait donner :

                        eeeee
                        eeeee
                        hello
                        eeeee
                        eeeee

                        Or, en essayant les scripts proposés, je n'arrive pas à ce résultat, soit

                        -dans le script avec, head et tail , des lignes sont ajoutées ; ainsi j'obtiens : cat yo :

                        eeeee
                        eeeee
                        eeeee
                        eeeee
                        hello
                        eeeee
                        eeeee
                        eeeee

                        Autrement dit, il me rajoute des lignes de texte, copies de lignes du texte, au texte

                        Ou alors, rien ne change dans les deux fichiers : fichier et yo

                        cat fichier :

                        eeeee
                        eeeee
                        eeeee
                        eeeee

                        cat yo

                        eeeee
                        eeeee
                        eeeee
                        eeeee

                        Je ne suis pas sorti de l'auberge !

                        Merci tout de même

                        ps : scripts de ref.:
                        ---------------------------

                        #! /bin/bash

                        centre1=$(expr $(wc -l $2 | cut -d" " -f1) / 2)
                        centre2=$(($centre1 +1))
                        head -"$centre" "$2" > fichier
                        echo "$1" >> fichier
                        tail -"$centre2" "$2" >> fichier

                        rem.: centre, n'est pas une variable. Or vous lui demandez une valeur!
                        fichier, sort yo, et l'insertion 'hello' mais avec des copies de lignes en plus. ce qui fait que l'insertion n'apparait pas au milieu.
                        ------------------------------------

                        ! /bin/bash

                        echo "$1" > tmp
                        milieu=$(expr $(wc -l $2 | cut -d" " -f1) / 2)
                        split -l "$milieu" bar.txt tmp
                        cat tmpaa tmp tmpab > fichier
                        rm -f tmp*

                        rem.: fichier tmpaa,, tmpab, n'existent pas
                        bar changé par mon fichier
                        1. bonjour,

                          J'obtiens bien ce que je voudrais avec ce script (logique): sh mo hello yo , mais pas où, il fallait.

                          #! /bin/bash

                          milieu=$(expr $(wc -l $2 | cut -d" " -f1) / 2)
                          head -"$milieu" "$2" > fichier
                          echo "$1" >> fichier
                          tail -"$milieu" "$2" >> fichier

                          cat yo

                          eeeee
                          eeeee
                          eeeee
                          eeeee

                          donc, échec, toujours ....

                          mais sur fichier : cat fichier :

                          eeeee
                          eeeee
                          hello
                          eeeee
                          eeeee

                          je voudrais ce résultat aussi dans yo!

                          Je ne suis pas au bout du roulot ....

                          merci
                          1. Je l'ai eu !

                            En partant du script de jipicy (le 2e), que je remercie au passage, plus simple et plus judicieux (le premier, j'ai eu du mal ,avec split!), j'ai demandé à la fin, tout simplement de 'mv fichier yo', et le tour (le tout aussi) était joué!

                            j'avais enfin, non de dieu ! ce que je voulais :

                            eeeee
                            eeeee
                            hello
                            eeeee
                            eeeee

                            j'aurais du venir sur votre site plus tôt : seul, on a toujours plus de mal, malgré le cours et du matériel qu'on peut trouver ailleurs. Mais c'est dans l'échange "vive et animé", ou en collectif, qu'on avance, en testant les solutions, en les remaniant, en tentant de comprendre leur logique.

                            j'ai passé la nuit entière là-dessus, mais cette fois, ça y est, j'ai enfin réussi. cela faisait des jours, que j'étais là-dessus, mais tout seul, pas facile, même si on avance un peu, mais pas autant que quand on est épaulé !

                            Merci à vous, Merci aux contributeurs
                            1. bonjour,

                              je reviens vers vous, avec un problème, simple, mais je galère un peu ! je débute sérieusement sur unix.

                              pb : je fais une redirection de 'env' sous unix, donc, je vais avoir : pwd, user, mail, logname, home.

                              ex. : env > toi

                              je souhaite sortir (extraire) et afficher, numéro de ligne, ), nom de l'occurence, = , chaque occurrence de user (l'utilisateur qui exécute le script) , de cette façon:

                              1) pwd=
                              2) user=
                              jusqu'à
                              4) home=

                              et pouvoir aussi le faire autant de fois, que ces occurrences là, sont contenues dans le fichier : dans le cas, par ex., où je redirige plusieurs fois, env, dans le même fichier, toi.

                              travail déjà effectué : j'ai essayé par ex. : find / -pwd 'toi' ( pour faire un premier test: décomposer tout pb, en pbs, plus simples), mais, j'ai eu le message d'erreur suivant :
                              find: invalid predicate `-pwd'

                              je continue la recherche.

                              Merci pour votre aide d'avance
                              1. Modérateur
                                Salut,

                                Un truc dans ce genre :
                                $ env | egrep "^(HOME|USER|PWD|SHELL)" | cat -n
                                     1  SHELL=/bin/bash
                                     2  USER=jp
                                     3  PWD=/home/jp/tmpfs
                                     4  HOME=/home/jp
                                ;-))
                                1. Bonjour,

                                  J'ai avancé. C'est grep, qu'il faut utiliser.
                                  J'ai redirigé 3 fois, ma sortie (env > toi (*3))

                                  Ainsi, j'obtiens :

                                  PWD=
                                  PWD=
                                  PWD=

                                  Ce que je veux, c'est :

                                  1) PWD=
                                  2) PWD=
                                  3) PWD=

                                  Et ceci pour les autres occurrences aussi, bien sûr : tout cela redirigé vers un fichier, dans un script.

                                  La recherche continue.

                                  Merci de votre contribution
                                  1. Effectivement j'ai oublié de mettre une ligne... ormalement avec ça a la fin ton fichier garderas le même nom
                                    cat temp > $2 | rm temp 
                                    , par contre moi il le met bien au millieu, je viens de réessayer sur un fichier de onze ligne et ca donné ca

                                    11111111111111111
                                    11111111111111111
                                    11111111111111111
                                    11111111111111111
                                    11111111111111111
                                    00000000000000000
                                    11111111111111111
                                    11111111111111111
                                    11111111111111111
                                    11111111111111111
                                    11111111111111111
                                    11111111111111111

                                    Maintenant si tu essaye avec un des scripts au dessus ça devrait donner ça, normalement.

                                    1111111111111
                                    0000000000000
                                    2222222222222
                                    1111111111111

                                    Je précise que le script que j'ai posté ne fonctionne que pour un nombres de lignes impair, avec un nombre de ligne pair, les scripts proposé au dessus fonctionne très bien, le problème c'est que a chaque fois il faut connaitre le nombre de lignes, ce qui serait intéressant c'est d'essayer de faire un fichier qui insère une ligne au milieu sans tenir compte du fait que le nombre de lignes soit pair ou impair.

                                    "j'aurais du venir sur votre site plus tôt : seul, on a toujours plus de mal, malgré le cours et du matériel qu'on peut trouver ailleurs"
                                    Oui les gens ici sont toujours prés à t'aider si de ton coté te fait un p'tit quelquechose, donc ceux qui attendent d'avoir une réponse toute cuite se gourre un peu, et c'est bien, c'est comme ça que l'on apprend, et si t'as des problémes pour tes scripts jipicy seras là :)))))) il m'as pas mal aidé pour mon script du jeu du pendu , si tu veux y jeter un coup d'oeil http://www.commentcamarche.net/forum/affich 3900064 script bash avance#0 regarde a la fin j'ai posté une version final, mais j y ai retrouvé quelque petites erreurs mais en gros ça marche comme il faut.

                                    Pour ton autre exercices le résultat final ce serait pas un truc du genre?

                                    1) PWD=/home/toi
                                    2) USER=toi
                                    3) MAIL=/var/spool/mail/toi
                                    4) LOGNAME=toi
                                    5) HOME=/home/toi
                                    ...

                                    Parce que j'ai du faire un exercice dans le même genre, j'avais la commande env redirigé 5 fois dans le fichier XX et je devais y rajouter le numero de la ligne plus une paranthése, donc si t'as besoin.... mais je pense que la soluce de jipicy devrait te satisfaire!?
                                    1. Modérateur
                                      Tiens, j'ai mieux encore :
                                      $ env | egrep "^(HOME|USER|PWD|SHELL)" | nl -w 1 -s ") "
                                      1) SHELL=/bin/bash
                                      2) USER=jp
                                      3) PWD=/home/jp/tmpfs
                                      4) HOME=/home/jp
                                      ;-))
                                      • 1
                                      • 2
                                      • 3