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 :

[sed] Modification d'une ligne dans un fichier


Sujet :

Shell et commandes GNU

  1. #1
    Membre très actif
    Profil pro
    ingénieur
    Inscrit en
    Novembre 2011
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : France, Tarn (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur

    Informations forums :
    Inscription : Novembre 2011
    Messages : 165
    Par défaut [sed] Modification d'une ligne dans un fichier
    Bonjour à tous,

    dans un fichier, j'ai une déclaration du type:

    ou (noter l'espace avant le dernier ')

    je dois

    1- pouvoir ajouter une chaine $1='chaine' à la fin :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ma_var='1.0 2.0 2.1 chaine'
    2- pouvoir supprimer la chaine $1=n'importe quelle chaine de la déclaration. Par exemple si $1='2.0':
    j'ai tenté plein de trucs avec sed -i, mais j'ai toujours des effets de bords (ce que je ne peux pas me permettre).
    Si un pro du sed peux m'aider

  2. #2
    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,

    n'étant pas un pro de sed je te proposerais une solution à base de perl qui a malgré tout le mérite de faire le job avec un formatage propre derrière

    le fichier de test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ cat fichier
    pouet=gruik
    ma_var='5.0 6.2.8 7.0 '
    machin=coincoin
    la suppression :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    $ toto=6.2.8
    $ perl -i -plane 'if ($_ =~ /ma_var=\x27(.+?) *\x27/){@tab=split(" ", $1); @tab = grep (!/'${toto}'/, @tab); $_ = "ma_var=\x27" . join(" ", @tab) . "\x27";}' fichier
    $ cat fichier
    pouet=gruik
    ma_var='5.0 7.0'
    machin=coincoin
    l'ajout :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    $ toto="10.32"
    $ perl -i -plane 'if ($_ =~ /ma_var=\x27(.+?) *\x27/){@tab=split(" ", $1); push (@tab, "'${toto}'"); $_ = "ma_var=\x27" . join(" ", @tab) . "\x27";}' fichier
    $ cat fichier
    pouet=gruik
    ma_var='5.0 7.0 10.32'
    machin=coincoin

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

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

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ sed '/^ma_var=/s/\x27$/'"$toto"'\x27/' /tmp/fichier
    pouet=gruik
    ma_var='5.0 6.2.8 7.0 koko'
    machin=coincoin
    $ sed '/^ma_var=/s/\x27$/'"$toto"'\x27/' /tmp/fichier > /tmp/fichier2
    $ sed '/^ma_var=/s/'"$toto"'//' /tmp/fichier2
    pouet=gruik
    ma_var='5.0 6.2.8 7.0 '
    machin=coincoin

  4. #4
    Membre très actif
    Profil pro
    ingénieur
    Inscrit en
    Novembre 2011
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : France, Tarn (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur

    Informations forums :
    Inscription : Novembre 2011
    Messages : 165
    Par défaut
    Citation Envoyé par Flodelarab Voir le message
    Bonjour,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ sed '/^ma_var=/s/\x27$/'"$toto"'\x27/' /tmp/fichier
    pouet=gruik
    ma_var='5.0 6.2.8 7.0 koko'
    machin=coincoin
    $ sed '/^ma_var=/s/\x27$/'"$toto"'\x27/' /tmp/fichier > /tmp/fichier2
    $ sed '/^ma_var=/s/'"$toto"'//' /tmp/fichier2
    pouet=gruik
    ma_var='5.0 6.2.8 7.0 '
    machin=coincoin
    merci (merci aussi à bufferBob )

    j'obtiens ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ cat essai.txt
    CMD_DIR=`dirname $0`
    VERSIONS='3.3.1 3.3 3.4 3.2.2 3.2.1 3.2 3.1.1 next'
    CMD=`basename $0`
    $ setenv toto 3.3
    $ sed '/^VERSIONS=/s/\x27$/'"$toto"'\x27/' essai.txt
    CMD_DIR=`dirname $0`
    VERSIONS='3.3.1 3.3 3.4 3.2.2 3.2.1 3.2 3.1.1 next3.3'
    CMD=`basename $0`
    $ sed --version
    GNU sed version 4.1.5

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 298
    Par défaut
    L'ordinateur fait toujours ce que je demande et jamais ce que je veux.
    Certes.

    Veuillez reformuler la question pour avoir la réponse idoine.

  6. #6
    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 Flodelarab Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $ sed '/^ma_var=/s/\x27$/'"$toto"'\x27/' /tmp/fichier
    (...)
    $ sed '/^ma_var=/s/'"$toto"'//' /tmp/fichier2
    rahh comme c'est bien vu, si j'ai bien compris ça fonctionne comme awk pour le coup, /match/s/regex/substitution/, je connaissais pas du tout cette tournure

    par contre -et c'est le propos du dernier post de tiresias54 si j'ai bien suivi- la sortie est pas super carrée, du coup si on fait tourner plusieurs fois ajout/suppression on peut potentiellement se retrouver avec pleins d'espaces en début/fin de ligne et entre les valeurs également

    il suffit d'une légère amélioration :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    $ cat fichier
    pouet=gruik
    ma_var='5.0 7.0 10.32'
    machin=coincoin
    $ toto=koko
    $ sed -i '/^ma_var=/s/\x27$/ '"$toto"'\x27/' fichier  # ajout
    $ grep ma_var fichier
    ma_var='5.0 7.0 10.32 koko'
    $ toto="7.0"
    $ sed -i '/^ma_var=/s/'"$toto"' \?//;s/ $//' fichier   # suppression
    $ grep ma_var fichier
    ma_var='5.0 10.32 koko'
    là on est bon

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 298
    Par défaut
    Hum. Pardon. Mais je crois que le problème n'est pas dans l'espace. Il demande de rajouter à la fin et quand on rajoute à la fin, il se rend compte que c'est au milieu qu'il voulait le rajouter ... y a un moment, il faut qu'il définisse le milieu

    si j'ai bien compris ça fonctionne comme awk
    Exactement. Tu peux aussi faire des trucs comme:
    Ici, on ne remplace que de la ligne 4 à la ligne 13 4,13s/bloblo//g ,
    Là, on ne remplace que sur un bloc qui part de la ligne contenant truc vers la ligne contenant muche /truc/,/muche/s/bla/bli/g ,
    Et là, on remplace ce qui a correspondu /zozo.*P/s//zazapouet/

  8. #8
    Membre très actif
    Profil pro
    ingénieur
    Inscrit en
    Novembre 2011
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : France, Tarn (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur

    Informations forums :
    Inscription : Novembre 2011
    Messages : 165
    Par défaut
    c'était effectivement un problème d'espace. Merci à vous 2

    je vais maintenant essayer de comprendre en détail la commande

  9. #9
    Membre très actif
    Profil pro
    ingénieur
    Inscrit en
    Novembre 2011
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : France, Tarn (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur

    Informations forums :
    Inscription : Novembre 2011
    Messages : 165
    Par défaut
    Bon en fait la solution proposée par BufferBob fonctionne .... presque
    Il y a deux problèmes:

    1- l'instruction s/ $// qui permet de supprimer les espaces ajoutés à la fin ne fonctionne pas car il manque la quote de fermeture. Il faudrait écrire (j'ai ajouté le g pour supprimer les espaces de manière récurcive):
    mais ça ne fonctionne pas .... j'ai l'erreur:


    2- si un des string présent dans ma_var contient $toto comme sous-string, alors ça foire (il supprime le premier sous-string qu'il trouve - ou bien tous les sous-string si on ajoute l'option récurcive g):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    $ cat essai
    #!/bin/bash
    ma_var='3 3.3.1 3.3 3.4 3.2.2 3.2.1 3.2 3.1.1 next      '
    $ sed '/^ma_var=/s/'"3"' \?//g;s/ $//g' ./essai
    #!/bin/bash
    ma_var='..1 ..4 .2.2 .2.1 .2 .1.1 next      '

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 298
    Par défaut
    j'obtiens ceci :

    $ cat essai.txt
    CMD_DIR=`dirname $0`
    VERSIONS='3.3.1 3.3 3.4 3.2.2 3.2.1 3.2 3.1.1 next'
    CMD=`basename $0`
    $ setenv toto 3.3
    $ sed '/^VERSIONS=/s/\x27$/'"$toto"'\x27/' essai.txt
    CMD_DIR=`dirname $0`
    VERSIONS='3.3.1 3.3 3.4 3.2.2 3.2.1 3.2 3.1.1 next3.3'
    CMD=`basename $0`
    $ sed --version
    GNU sed version 4.1.5
    Et alors ? Quel est le problème ? Arrête de faire des effets d'yeux et fais une phrase en français pour exprimer le problème.

    Illegal variable name
    Rien d'étonnant que tu aies une erreur puisque tu as un nombre impaire de quotes. Débrouille-toi autrement. Avec des double-quotes ou un anti-slash à l'extérieur.

    (j'ai ajouté le g pour supprimer les espaces de manière récurcive)
    Là, tu rêves. g n'est pas récursif mais répétitif.

    Est-ce qu'on pourra finalement avoir la vraie question initiale?

  11. #11
    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 tiresias54,

    Citation Envoyé par tiresias54 Voir le message
    1- l'instruction s/ $// qui permet de supprimer les espaces ajoutés à la fin ne fonctionne pas car il manque la quote de fermeture.
    exact, my mistake , la ligne suivante est plus solide et devrait fonctionner avec tous les cas de figure, en revanche il y a peut-être plus concis et dans tous les cas ça commence à être un peu lourd comme traitement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $ toto="3.5"
    $ sed -e '/^ma_var=/s/\x27\s*\(.*\)'"$toto"'\(.*\)\x27.*$/\x27\1\2\x27/;s/  */ /g;s/ *\x27$/\x27/g' <<< "ma_var='   1.8    3.5   5.9   '"
    ma_var='1.8 5.9'
    2- si un des string présent dans ma_var contient $toto comme sous-string, alors ça foire (il supprime le premier sous-string qu'il trouve - ou bien tous les sous-string si on ajoute l'option récurcive g)
    là pour le coup je rejoins ce que disait Flodelarab tu aurais du mieux définir ton besoin dès le départ, vu sous cet angle à mon avis ce n'est pas faisable directement à coups de sed
    j'en reviens donc à ma première solution en perl (très légèrement modifiée) qui bénéficie à la fois de la fonction split() et à la fois d'effectuer une substitution inplace :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    $ toto="3"
    $ perl -i -plane '
    if ($_ =~ /ma_var=\x27(.+?) *\x27/) {              # on match + capture l affectation de la variable
        @tab = split(" ", $1);                         # on split la chaine, ce qui va nous permettre
        @tab = grep (!/^\Q'${toto}'\E$/, @tab);        # de matcher de manière formelle notre numero de version (on notera l emploi de \Q et \E, quote et endquote)
        $_ = "ma_var=\x27" . join(" ", @tab) . "\x27"; # on affiche le resultat
    }' <<< "ma_var='   1.3    3   3.7   '"
    ma_var='1.3 3.7'

  12. #12
    Membre très actif
    Profil pro
    ingénieur
    Inscrit en
    Novembre 2011
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : France, Tarn (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur

    Informations forums :
    Inscription : Novembre 2011
    Messages : 165
    Par défaut
    ok, j'ai essayé d'être trop général je pense, d'où une formulation bancale.
    J'essaie de reformule en étant plus concret:

    Dans un fichier, une variable ma_var contient une liste de versions d'un outil séparées par des espaces:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ma_var='1.0 2.0 2.1 1.0 2.2.1 3'
    Je dois pouvoir modifier la déclaration de cette variable directement dans le fichier (d'où l'utilisation de sed -i) pour ajouter ou supprimer une version à volonté, sachant que:

    1- pour l'ajout, il faut qu'il soit fait en fin de déclaration
    2- pour la suppression: parfois un numéro de version est dupliqué (par exemple dans ma_var ci-dessus, la version 1.0 apparait 2 fois)!

    J'espère que cette fois-ci c'est plus compréhensible.

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 298
    Par défaut
    j'ai essayé d'être trop général je pense
    Ou trop particulier, au contraire. Tu résous un problème et après tu te rends compte que c'est pas ce que tu cherchais.

    Dans un fichier, une variable ma_var contient une liste de versions d'un outil séparées par des espaces:
    Stop. Déjà, là, c'est pas bon. Pourquoi n'as-tu pas un fichier avec une version par ligne ? Tu manipules alors le fichier avec tous les outils de console qui travaillent sur les lignes. Et pas cette variable boiteuse.

    C'est quoi le but final ?

    (bis repetita placent)

  14. #14
    Membre très actif
    Profil pro
    ingénieur
    Inscrit en
    Novembre 2011
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : France, Tarn (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur

    Informations forums :
    Inscription : Novembre 2011
    Messages : 165
    Par défaut
    Citation Envoyé par Flodelarab Voir le message
    Ou trop particulier, au contraire. Tu résous un problème et après tu te rends compte que c'est pas ce que tu cherchais.

    Stop. Déjà, là, c'est pas bon. Pourquoi n'as-tu pas un fichier avec une version par ligne ? Tu manipules alors le fichier avec tous les outils de console qui travaillent sur les lignes. Et pas cette variable boiteuse.

    C'est quoi le but final ?

    (bis repetita placent)
    Malheureusement ça n'est pas moi qui ait écrit ces fichiers avec ces déclarations boiteuses, je dois faire avec tels qu'ils sont.

    Donc l'existant c'est: dans un fichier (qui est un script bash en fait), on a une déclaration d'une variable ma_var qui contient une liste de versions séparées par des espaces. Ce script permet le lancement d'un outil installé sur le système. Je ne peux modifier que cette variable dans le script.

    Le but final c'est:
    1- lorsqu'on installe une nouvelle version de l'outil, on ajoute la version en question à la fin de la déclaration de la variable ma_var dans le fichier qui la contient.
    2- lorsqu'on supprime une version de l'outil, on supprime toutes les occurrences (oui je sais c'est horrible qu'il y ait plusieurs fois la même version déclarée) de la version en question de la déclaration de ma_var dans le script.

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 298
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ sed '/^ma_var=/s/\x27 *$/'"$toto"'\x27/' /tmp/fichier
    pouet=gruik
    ma_var='5.0 6.2.8 7.0 koko'
    machin=coincoin
    $ sed '/^ma_var=/s/\x27 *$/'"$toto"'\x27/' /tmp/fichier >/tmp/fichier2
    $ sed '/^ma_var=/s/ *'"$toto"' */ /g' /tmp/fichier2
    pouet=gruik
    ma_var='5.0 6.2.8 7.0 '
    machin=coincoin

  16. #16
    Membre très actif
    Profil pro
    ingénieur
    Inscrit en
    Novembre 2011
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : France, Tarn (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur

    Informations forums :
    Inscription : Novembre 2011
    Messages : 165
    Par défaut
    super merci à vous 2!

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 08/08/2009, 18h05
  2. [FSO] Effacer une ligne dans un fichier
    Par Johnbob dans le forum ASP
    Réponses: 4
    Dernier message: 30/05/2007, 16h23
  3. [VBA] insérer une ligne dans un fichier excel
    Par cokinoumasterflash dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 21/07/2005, 18h52
  4. [langage] Effacer une ligne dans un fichier
    Par sebi77 dans le forum Langage
    Réponses: 2
    Dernier message: 01/01/2005, 12h43
  5. Supprimer une ligne dans un fichier
    Par sbeu dans le forum Langage
    Réponses: 3
    Dernier message: 13/05/2003, 10h30

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