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 :

Utiliser sed pour réécrire certaines lignes d'un fichier ?


Sujet :

Shell et commandes GNU

  1. #1
    Membre du Club
    Profil pro
    Futur administrateur systèmes
    Inscrit en
    Décembre 2010
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Futur administrateur systèmes

    Informations forums :
    Inscription : Décembre 2010
    Messages : 57
    Points : 49
    Points
    49
    Par défaut Utiliser sed pour réécrire certaines lignes d'un fichier ?
    Bonjour,

    Je suis confronté à un problème avec la commande sed.

    Voici le type de fichier que j'ai :

    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
    30
    31
    32
    33
    34
    2019-10-29-06-00;/dev/xx;512.00;295.16;/opt/
    2019-10-29-06-00;/dev/xx;128.00;106.54;/var/
    2019-10-29-06-00;/dev/xx;256.00;180.79;/usr/
    2019-10-29-06-00;/dev/xx;384.00;191.13;/var/
    2019-10-29-06-00;/dev/xx;256.00;255.37;/var/
    2019-10-29-06-00;/dev/xx;3200.00;2679.36;/var/opt/
    2019-10-29-06-00;/dev/xx;256.00;255.07;/var/
    2019-10-29-06-00;/dev/xx;64.00;62.67;/etc/
    2019-10-29-06-00;/dev/xx;1664.00;1163.33;/opt
    2019-10-29-06-00;/dev/xx;256.00;146.13;/opt/
    2019-10-29-06-00;/dev/xx;2176.00;952.90;/opt/
    2019-10-29-06-00;/dev/xx;22784.00;10353.91;/opt/
    2019-10-29-06-00;/dev/xx;256.00;253.64;/
    2019-10-29-12-00;/dev/xx;256.00;229.92;/home
    2019-10-29-12-00;/dev/xx;1024.00;556.73;/opt
    2019-10-29-12-00;/dev/xx;256.00;180.79;/usr/
    2019-10-29-12-00;/dev/xx;384.00;190.90;/var
    2019-10-29-12-00;/dev/xx;256.00;255.37;/var/
    2019-10-29-12-00;/dev/xx;128.00;127.63;/
    2019-10-29-12-00;/dev/xx;256.00;76.86;/opt/
    2019-10-29-12-00;/dev/xx;2176.00;1682.93;/opt/
    2019-10-29-12-00;/dev/xx;256.00;145.66;/opt/
    2019-10-29-12-00;/dev/xx;2176.00;952.90;/opt/
    2019-10-29-12-00;/dev/xx;22784.00;10421.72;/opt/
    2019-10-29-12-00;/dev/xx;256.00;253.64;/
    2019-10-29-18-00;/dev/xx;1024.00;138.8;/
    2019-10-29-18-00;/dev/xx;5248.00;4230.34;/usr
    2019-10-29-18-00;/dev/xx;2560.00;499.37;/var
    2019-10-29-18-00;/dev/xx;3584.00;67.79;/tmp
    2019-10-29-18-00;/dev/xx;256.00;25.9;/home
    2019-10-29-18-00;/dev/xx;1024.00;467.27;/opt
    2019-10-29-18-00;/dev/xx;384.00;0.38;/usr/
    2019-10-29-18-00;/dev/xx;256.00;21.36;/
    2019-10-29-18-00;/dev/xx;512.00;216.84;/opt/

    Je souhaite, dans mon fichier, ne modifier que les lignes allant du début juqu'à la dernière ligne comprenant 2019-10-29-12-00 pour soustraire la valeur $3 à la valeur $4 et que ce résultat prenne la place de la valeur $4. J'arrive à ne cibler ces lignes qu'avec la commande :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sed '/2019-10-29-12-00/{:a;n;//ba;Q}' test2.txt
    Ce qui donne :

    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
    2019-10-29-06-00;/dev/xx;512.00;295.16;/opt/
    2019-10-29-06-00;/dev/xx;128.00;106.54;/var/
    2019-10-29-06-00;/dev/xx;256.00;180.79;/usr/
    2019-10-29-06-00;/dev/xx;384.00;191.13;/var/
    2019-10-29-06-00;/dev/xx;256.00;255.37;/var/
    2019-10-29-06-00;/dev/xx;3200.00;2679.36;/var/opt/
    2019-10-29-06-00;/dev/xx;256.00;255.07;/var/
    2019-10-29-06-00;/dev/xx;64.00;62.67;/etc/
    2019-10-29-06-00;/dev/xx;1664.00;1163.33;/opt
    2019-10-29-06-00;/dev/xx;256.00;146.13;/opt/
    2019-10-29-06-00;/dev/xx;2176.00;952.90;/opt/
    2019-10-29-06-00;/dev/xx;22784.00;10353.91;/opt/
    2019-10-29-06-00;/dev/xx;256.00;253.64;/
    2019-10-29-12-00;/dev/xx;256.00;229.92;/home
    2019-10-29-12-00;/dev/xx;1024.00;556.73;/opt
    2019-10-29-12-00;/dev/xx;256.00;180.79;/usr/
    2019-10-29-12-00;/dev/xx;384.00;190.90;/var
    2019-10-29-12-00;/dev/xx;256.00;255.37;/var/
    2019-10-29-12-00;/dev/xx;128.00;127.63;/
    2019-10-29-12-00;/dev/xx;256.00;76.86;/opt/
    2019-10-29-12-00;/dev/xx;2176.00;1682.93;/opt/
    2019-10-29-12-00;/dev/xx;256.00;145.66;/opt/
    2019-10-29-12-00;/dev/xx;2176.00;952.90;/opt/
    2019-10-29-12-00;/dev/xx;22784.00;10421.72;/opt/
    2019-10-29-12-00;/dev/xx;256.00;253.64;/

    Et soustraire les valeurs :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sed '/2019-10-29-12-00/{:a;n;//ba;Q}' test2.txt | awk -F';' '{print $1";"$2";"$3";"($3 - $4)";"$5}'
    Ce qui donne :

    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
    2019-10-29-06-00;/dev/xx;512.00;216.84;/opt/
    2019-10-29-06-00;/dev/xx;128.00;21.46;/var/
    2019-10-29-06-00;/dev/xx;256.00;75.21;/usr/
    2019-10-29-06-00;/dev/xx;384.00;192.87;/var/
    2019-10-29-06-00;/dev/xx;256.00;0.63;/var/
    2019-10-29-06-00;/dev/xx;3200.00;520.64;/var/opt/
    2019-10-29-06-00;/dev/xx;256.00;0.93;/var/
    2019-10-29-06-00;/dev/xx;64.00;1.33;/etc/
    2019-10-29-06-00;/dev/xx;1664.00;500.67;/opt
    2019-10-29-06-00;/dev/xx;256.00;109.87;/opt/
    2019-10-29-06-00;/dev/xx;2176.00;1223.1;/opt/
    2019-10-29-06-00;/dev/xx;22784.00;12430.1;/opt/
    2019-10-29-06-00;/dev/xx;256.00;2.36;/
    2019-10-29-12-00;/dev/xx;256.00;26.08;/home
    2019-10-29-12-00;/dev/xx;1024.00;467.27;/opt
    2019-10-29-12-00;/dev/xx;256.00;75.21;/usr/
    2019-10-29-12-00;/dev/xx;384.00;193.1;/var
    2019-10-29-12-00;/dev/xx;256.00;0.63;/var/
    2019-10-29-12-00;/dev/xx;128.00;0.37;/
    2019-10-29-12-00;/dev/xx;256.00;179.14;/opt/
    2019-10-29-12-00;/dev/xx;2176.00;493.07;/opt/
    2019-10-29-12-00;/dev/xx;256.00;110.34;/opt/
    2019-10-29-12-00;/dev/xx;2176.00;1223.1;/opt/
    2019-10-29-12-00;/dev/xx;22784.00;12362.3;/opt/
    2019-10-29-12-00;/dev/xx;256.00;2.36;/

    Mais là ça s'affiche juste dans mon terminal... Et si je redirige cette commande vers un fichier externe, cela va me créer un fichier qu'avec les lignes modifier. Or, moi je voudrais apporter ces modifications dans mon fichier sans perdre le reste des lignes.


    Auriez-vous une solution ?


    Merci d'avance !

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 243
    Points : 13 458
    Points
    13 458
    Par défaut
    Bonjour

    Ben oui : arrête d'utiliser sed.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    awk -F';' '/2019-10-29-12-00/{OFS=FS;$4=$3-$4;} 1' fichier.txt
    Remarque quand même que ta méthode est sale. Comment vas-tu différencier le fichier original et celui modifié ?
    Cette réponse vous apporte quelque chose ? Cliquez sur en bas à droite du message.

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 550
    Points : 19 383
    Points
    19 383
    Par défaut
    j'ai compris que le calcul doit être fait depuis la première ligne jusqu'au dernier 2019-10-29-12-00
    ne modifier que les lignes allant du début juqu'à la dernière ligne comprenant 2019-10-29-12-00
    soit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    gawk -F ';' 'NR>=1 && noGo==0 || /^2019-10-29-12-00/{if(/^2019-10-29-12-00/)noGo=1;$4=$3-$4}1'
    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  4. #4
    Membre du Club
    Profil pro
    Futur administrateur systèmes
    Inscrit en
    Décembre 2010
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Futur administrateur systèmes

    Informations forums :
    Inscription : Décembre 2010
    Messages : 57
    Points : 49
    Points
    49
    Par défaut
    Hello !

    Tout d'abord merci pour votre aide !


    Je sais que ma méthode est sale, voilà pourquoi je suis venu me faire corriger ici !
    Cela dit, si je n'avais pas trouvé de moyen pour réécrire directement dans mon fichier, je serais très certainement passé par un fichier temporaire. J'aurai ensuite fait un mv pour récupérer le nom du fichier de base.

    Tout ce qui est OFS/FS/NR/FNR et tout ce qui va avec, reste pour moi une source de difficulté. Je n'arrive jamais à les utiliser, je reste bloqué à une utilisation basique d'awk.


    Je m'en vais de ce pas tester vos commandes ! Merci encore !

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 550
    Points : 19 383
    Points
    19 383
    Par défaut
    je suis venu me faire corriger ici
    bienvenue

    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 243
    Points : 13 458
    Points
    13 458
    Par défaut
    j'ai compris que le calcul doit être fait depuis la première ligne jusqu'au dernier 2019-10-29-12-00
    Le tout est de savoir si, dans la phrase originale, "comprenant" se réfère à "les lignes" ou à "la dernière ligne".

    NR>=1
    Peux-tu citer un cas où NR ne vérifie pas cette condition ?
    Cette réponse vous apporte quelque chose ? Cliquez sur en bas à droite du message.

  7. #7
    Membre éprouvé Avatar de balkany
    Homme Profil pro
    Touriste
    Inscrit en
    Juillet 2017
    Messages
    346
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Touriste

    Informations forums :
    Inscription : Juillet 2017
    Messages : 346
    Points : 977
    Points
    977
    Par défaut
    Citation Envoyé par Ezzmazz Voir le message
    Mais là ça s'affiche juste dans mon terminal... Et si je redirige cette commande vers un fichier externe, cela va me créer un fichier qu'avec les lignes modifier. Or, moi je voudrais apporter ces modifications dans mon fichier sans perdre le reste des lignes.
    Avec gawk, tu peux émuler le comportement de sed -i via le mécanisme d'inclusion :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    gawk -i inplace 'programme-awk' fichier.txt
    Cf. https://www.gnu.org/software/gawk/ma...e-Inplace.html

  8. #8
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 278
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 278
    Points : 12 726
    Points
    12 726
    Par défaut
    Citation Envoyé par balkany Voir le message
    Avec gawk, tu peux émuler le comportement de sed -i via le mécanisme d'inclusion :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    gawk -i inplace 'programme-awk' fichier.txt
    Cf. https://www.gnu.org/software/gawk/ma...e-Inplace.html
    Oui, mais tout comme pour sed, on doit tout de même afficher les ligne que l'on ne modifie pas sinon celles-ci ne seront plus dans le fichier.

    Le "inplace" de sed ou de awk, ne fait qu'ouvrir le fichier d'origine, une fois ouvert, il l'efface du système et crée un nouveau fichier du même nom.

    D'ailleurs, le "inplace" sans backup n'est pas conseillé, puisqu'on perd tout ou une partie si lors de l'exécution, le système plante.
    Cordialement.

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 550
    Points : 19 383
    Points
    19 383
    Par défaut
    Peux-tu citer un cas où NR ne vérifie pas cette condition ?


    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 243
    Points : 13 458
    Points
    13 458
    Par défaut
    Tout ce qui est OFS/FS/NR/FNR et tout ce qui va avec, reste pour moi une source de difficulté.
    Probablement car tu ne relies pas ces acronymes aux mots complets.
    • FS = Field Separator = séparateur de champ. Tu sais ce que c'est puisque tu l'as fixé avec l'option -F ';'. On aurait put écrire BEGIN{FS=";";} mais c'est plus long.
    • OFS = Output Field Separator = séparateur de champ en sortie. L'autre (FS) est donc en entrée. Si tu ne dis pas que c'est le même, il va remplacer les points-virgules par des espaces. Dans ma proposition, j'aurais pu éviter d'affecter OFS autant de fois qu'il y a de lignes, par une entête du type :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      awk -F';' -vOFS=';' '/2019-10-29-12-00/{$4=$3-$4;} 1' fichier.txt
    • NR = Number of Records = nombre d'enregistrements. Nombre d'enregistrements lus jusqu'ici. Par défaut, le nombre de lignes.
    • FNR = File Number of Records = nombre d'enregistrements du fichier. Remis à 0 pour chaque fichier en entrée.
    • RS = Record Separator = séparateur d'enregistrement. Au lieu de considérer le fichier texte composé de lignes comme enregistrements et de mots comme champs, on va choisir un autre caractère pour définir les limites des enregistrements.
    • ORS = Output Record Separator = séparateur d'enregistrement en sortie.L'autre (RS) est donc en entrée. Attention quand même avec ORS : un fichier texte doit finir par \n.
    • NF = Number of Fields = nombre de champs. C'est ce qui permet d'écrire $NF pour désigner le dernier champ.
    Cette réponse vous apporte quelque chose ? Cliquez sur en bas à droite du message.

  11. #11
    Membre du Club
    Profil pro
    Futur administrateur systèmes
    Inscrit en
    Décembre 2010
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Futur administrateur systèmes

    Informations forums :
    Inscription : Décembre 2010
    Messages : 57
    Points : 49
    Points
    49
    Par défaut
    Citation Envoyé par N_BaH Voir le message
    bienvenue

    Merci


    Citation Envoyé par Flodelarab Voir le message
    Probablement car tu ne relies pas ces acronymes aux mots complets.
    • FS = Field Separator = séparateur de champ. Tu sais ce que c'est puisque tu l'as fixé avec l'option -F ';'. On aurait put écrire BEGIN{FS=";";} mais c'est plus long.
    • OFS = Output Field Separator = séparateur de champ en sortie. L'autre (FS) est donc en entrée. Si tu ne dis pas que c'est le même, il va remplacer les points-virgules par des espaces. Dans ma proposition, j'aurais pu éviter d'affecter OFS autant de fois qu'il y a de lignes, par une entête du type :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      awk -F';' -vOFS=';' '/2019-10-29-12-00/{$4=$3-$4;} 1' fichier.txt
    • NR = Number of Records = nombre d'enregistrements. Nombre d'enregistrements lus jusqu'ici. Par défaut, le nombre de lignes.
    • FNR = File Number of Records = nombre d'enregistrements du fichier. Remis à 0 pour chaque fichier en entrée.
    • RS = Record Separator = séparateur d'enregistrement. Au lieu de considérer le fichier texte composé de lignes comme enregistrements et de mots comme champs, on va choisir un autre caractère pour définir les limites des enregistrements.
    • ORS = Output Record Separator = séparateur d'enregistrement en sortie.L'autre (RS) est donc en entrée. Attention quand même avec ORS : un fichier texte doit finir par \n.
    • NF = Number of Fields = nombre de champs. C'est ce qui permet d'écrire $NF pour désigner le dernier champ.
    Merci pour ces explications ! C'est beaucoup plus compréhensible !

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

Discussions similaires

  1. [XL-2007] Formule qui ne fonctionne pas pour une certaine ligne.
    Par ESVBA dans le forum Excel
    Réponses: 11
    Dernier message: 20/01/2016, 11h56
  2. [PowerShell] Comment récupérer certaines lignes d'un fichier pour ensuite s'en servir
    Par Zipper963 dans le forum Scripts/Batch
    Réponses: 5
    Dernier message: 13/12/2012, 15h35
  3. [XL-2007] Une macro pour copier seulement certaines lignes d'un fichier à un autre
    Par asgard78 dans le forum Macros et VBA Excel
    Réponses: 5
    Dernier message: 05/10/2010, 14h10
  4. Réponses: 3
    Dernier message: 25/12/2009, 09h29
  5. [MySQL] Couleur mauve pour représenter certaines lignes
    Par amazircool dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 03/01/2008, 14h57

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