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 :

Modification d'un fichier en cours de lecture


Sujet :

Shell et commandes GNU

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Bioinformaticien
    Inscrit en
    Février 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bioinformaticien
    Secteur : Santé

    Informations forums :
    Inscription : Février 2013
    Messages : 4
    Par défaut Modification d'un fichier en cours de lecture
    Bonjour,

    Peut-on modifier un fichier parcouru par une boucle for en Bash ?

    J'ai un fichier qui contient les bornes et la tailles de plusieurs axes qui peuvent être chevauchant. Exemple :
    Si on a ces 2 axes :
    10 _____ 22
    10 ___________ 30

    le fichier (tabulé) sera défini de la sorte :
    En parcourant le fichier, je supprime l'axes le plus court s'il y en a un de plus grande taille qui a la même origine.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    for i in `awk '{print $1}' file1` `awk '{print $2}'` file1
    do
       # traitement, recherche des doublons
         grep -v "$line_to_remove" file1 > file2
         mv file2 file1
    done
    Ça fonctionne sans problème mais j'aimerais savoir si c'était propre de procéder de la sorte car dans certains langage (ex : Python) cela provoquerait une erreur.

    Merci

  2. #2
    Expert confirmé Avatar de frp31
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Juillet 2006
    Messages
    5 196
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Juillet 2006
    Messages : 5 196
    Par défaut
    tu as plusieurs méthodes tout dépand du volume à traiter...

    inline en une passe un script awk ou sed sera mieux...

    avec un script qui traite chaque ligne

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while read
    do
    # traitement
    done < fichiersource >fichierresultat
    pour faire ça un for parait pas très pertinent mais c'est faisable aussi

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Bioinformaticien
    Inscrit en
    Février 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bioinformaticien
    Secteur : Santé

    Informations forums :
    Inscription : Février 2013
    Messages : 4
    Par défaut
    Ok, mais est-ce que le fait de modifier le contenu du fichier pendant qu'il est parcouru pose un problème ?

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 636
    Par défaut
    Bonjour,

    Citation Envoyé par Dan_121
    supprime l'axes le plus court s'il y en a un de plus grande taille qui a la même origine.
    quoi ça ? où ça ?
    merci de préciser, car il n'y a pas d'en-tête dans l'échantillon présenté.


    les données du fichier sont passées à la boucle une seule fois.
    le fichier n'est pas relu à chaque boucle.

    Il faut décrire précisément ce qui doit être fait.
    quelles actions
    quelles conditions subordonnent quelles actions
    ...
    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  5. #5
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 339
    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 339
    Par défaut
    Bonjour,

    Oui, si tu modifies un fichier pendant qu'il est parcouru, tu es dans un cas indéterminé.

    Par contre, dans ton exemple, tu n'es pas dans ce cas là:
    La liste pour le for est déterminée avant d' exécuter celle-ci (c'est la raison pour laquelle on lui préfère while) .

    Et lorsque tu supprimes les lignes depuis le grep, tu passes par un fichier intermédiaire.

    Sinon, je suis étonné que ta boucle fonctionne:
    sur la ligne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for i in `awk '{print $1}' file1` `awk '{print $2}'` file1
    le backquote de fin devrait être après file1
    De plus, la liste fournie au for serait dans l'ordre tout les arguments 1 du fichier file1 puis tous les arguments 2 du fichier file1.


    Cordialement.

  6. #6
    Futur Membre du Club
    Homme Profil pro
    Bioinformaticien
    Inscrit en
    Février 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bioinformaticien
    Secteur : Santé

    Informations forums :
    Inscription : Février 2013
    Messages : 4
    Par défaut
    Citation Envoyé par disedorgue Voir le message
    Sinon, je suis étonné que ta boucle fonctionne:
    sur la ligne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for i in `awk '{print $1}' file1` `awk '{print $2}'` file1
    le backquote de fin devrait être après file1
    De plus, la liste fournit au for serait dans l'ordre tout les arguments 1 du fichier file1 puis tous les arguments 2 du fichier file1.

    Cordialement.
    Oui oui, bien vu, erreur de frappe. Je m'en suis rendu compte après le poste.

    Citation Envoyé par N_BaH
    quoi ça ? où ça ?
    merci de préciser, car il n'y a pas d'en-tête dans l'échantillon présenté.
    Le fichier ressemble à peu prêt à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    start  end  size
    10  22  12
    10  30  20
    24  35  11
    28  35  7
    30  35  5
    40  68  28
    Je veux conserver la liste de fragments les plus longs pour chaque intervalle unique, c'est à dire obtenir après traitement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    start  end  size
    10  30  20
    24  35  11
    40  68  29
    Je conclus de vos différents commentaires que si la liste des positions start et end est déterminée une seule fois en début de boucle, le risque en supprimant des lignes dans le fichier pendant le parcourt serait de vouloir traiter des positions déjà supprimées. J'ai résolu ce problème en rajoutant
    "sort | uniq" à chaque liste d'arguments passé à la boucle for.
    Voici le code en entier :
    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
     
     
    #!/bin/bash
     
    cp $1 file1
     
    # Pour chaque position start et end on recupere les doublons
     
    for i in `awk '{print $1}' file1 | sort | uniq ` `awk '{print $2}' file1 | sort | uniq `
      do
     
        line=`grep -w $i file1 | tr '\n' ';' | awk '{print}' `
     
        #comptage du nombre de lignes recuperees
        nb_line=`grep -wc $i file1 `
        test=`echo "$nb_line" | awk '$1>1 {print}' `
     
        # s'il y a plusieurs lignes
        if [ "$test" != "" ]
          then
            # on cherche le fragment le plus long
            max="0"
            index_max="0"
     
            for ((j = 1 ; j <= $nb_line; j += 1))
              do
                size=`echo "$line" | cut -f "$j" -d ";" | cut -f 3 | awk '{print}' `
                if [ "$size" -gt "$max" ]
                  then
                    max="$size"
                    index_max="$j"
               fi
             done
     
             # on supprime les fragments les plus petits
             for ((k = 1 ; k <= $nb_line; k += 1))
               do
                 if [ "$k" -ne "$index_max" ]
                   then
                     line_to_remove=`echo "$line" | cut -f "$k" -d ";" | tr ";" "\n" | awk '{print}' `
                     # suppression des lignes du fichier
                     grep -v "$line_to_remove" file1 > file2
                     mv file2 file1
                 fi
            done
        fi
    done

  7. #7
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 102
    Par défaut
    Citation Envoyé par Dan_121 Voir le message
    Oui oui, bien vu, erreur de frappe. Je m'en suis rendu compte après le poste.
    Bonjour. Y a un bouton "EDIT" qui permet de corriger les erreurs de frappe!

    J'ai résolu ce problème en rajoutant "sort | uniq"
    Attention! Par défaut 'sort' fait un tri alphabétique: 1 10 100 11 19 2 20 21
    Tu veux probablement un tri numérique (option -n).
    De plus 'sort' gère aussi l'unicité (option -u).
    Tu peux donc remplacer avantageusement sort | uniq par sort -un.

  8. #8
    Futur Membre du Club
    Homme Profil pro
    Bioinformaticien
    Inscrit en
    Février 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bioinformaticien
    Secteur : Santé

    Informations forums :
    Inscription : Février 2013
    Messages : 4
    Par défaut
    Citation Envoyé par jack-ft
    Tu peux donc remplacer avantageusement sort | uniq par sort -un.
    Ok, merci

  9. #9
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 339
    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 339
    Par défaut
    Bonjour,

    pour un jeu de données tel que celui fourni ci-dessous, le résultat ne semble pas correct :

    données:résultat:Cordialement.

  10. #10
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 814
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 814
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Dan_121 Voir le message
    Bonjour,

    Peut-on modifier un fichier parcouru par une boucle for en Bash ?
    Bonjour
    C'est rigoureusement impossible car cela présuppose une redirection or celle-ci commence par vider le fichier de sortie.

    Donc toute modification d'un fichier lu passe par par un fichier intermédiaire comme le montre frp31. Toutefois il faut faire attention car tu es en multitâche donc cela suppose que ton script pourra tourner en parallèle sur plusieurs instances (risque de collision si le nom du fichier ne prend pas en compte un élément d'unicité comme le n° de processus $$).

    Toutefois il y a une méthode qui passe aussi par un fichier intermédiaire sauf que celui-ci est totalement géré par le shell donc t'as pas à te préoccuper de son nom. Il s'agit des canaux numérotés.

    Faut d'abord associer le fichier de travail à un canal numéroté. Comme 0, 1 et 2 sont déjà pris, le suivant est le 3

    Ensuite faut effacer le fichier parce qu'il devra être recréé mais faut pas que le nouveau soit lui-aussi associé au canal 3

    Enfin tu peux traiter le canal n° 3 (représentant l'ancien fichier) et créer le nouveau fichier en même temps
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while read line
    do
        travail $line
    done 0<&3 >file1

    Comme tu vois, c'est du "sans-filet" (suppression du fichier pendant le processus) mais en retour tu as l'impression de modifier le fichier que tu es en train de lire...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  11. #11
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 102
    Par défaut
    Citation Envoyé par Dan_121 Voir le message
    Oui oui, bien vu, erreur de frappe. Je m'en suis rendu compte après le poste.
    Afin de ne pas induire en erreur les futurs lecteurs de ce post (et au risque de me répéter), il n'est pas trop tard pour éditer le post en question et le corriger!

    Le fichier ressemble à peu prêt à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    start  end  size
    10  22  12
    10  30  20
    24  35  11
    28  35  7
    30  35  5
    40  68  28
    Je veux conserver la liste de fragments les plus longs pour chaque intervalle unique, c'est à dire obtenir après traitement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    start  end  size
    10  30  20
    24  35  11
    40  68  29
    Si j'ai bien compris, le fragment [24 35 11] recouvre et donc élimine le fragment inclus [28 35 7].
    Se peut-il qu'un fragment soit intégralement inclus dans un autre, sans aucune extrémité commune (comme [25 30 5] et [24 35 11], par exemple)?
    Auquel cas, les algorithmes à base de grep risquent de ne pas marcher!

    Même si cela n'est pas censé arriver, si je devais écrire le programme, je préfèrerais quand même qu'il traite le cas général!

    Si le fichier de données peut être très gros, je ne l'écrirais pas en shell!

    Sinon je mettrais tout en ram avec un algorithme simple (en O(N*(N+1)/2)):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Initialiser a vide une liste des lignes conservees
    Pour chaque ligne du fichier
        Pour chaque ligne conservee
            si la ligne conservee recouvre la ligne lue
            alors passer à la ligne suivante du fichier
            si la ligne lue recouvre la ligne conservee
            alors supprimer la ligne conservee de la liste des lignes conservees
            et passer a la ligne conservee suivante
        fin pour
        ajouter la ligne lue a la liste des lignes conservees
        et passer a la ligne lue suivante
    fin pour
    Afficher la liste des lignes conservees
    Si on n'est pas trop attaché à l'ordre final du résultat, on peut simplifier l'algorithme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Initialiser a vide une liste des lignes conservées
    Trier le fichier d entrée en ordre numérique croissant sur le 1er champ et décroissant sur le 2ème
    Pour chaque ligne du fichier trié
        Pour chaque ligne conservée
            si la ligne conservée recouvre la ligne lue
            alors passer à la ligne suivante du fichier
        fin pour
        ajouter la ligne lue a la liste des lignes conservées
    fin pour
    Afficher la liste des lignes conservées
    Y a plus qu'à coder...

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 636
    Par défaut
    une petite remarque : ce n'est pas parce que le pseudo-code en français dit pour chaque ligne, qu'il faut utiliser une boucle for.
    voir Comment lire/parser un fichier en shell.
    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  13. #13
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2006
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2006
    Messages : 247
    Billets dans le blog
    1
    Par défaut un coup a l'endroit, un coup a l'envers
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sort -nr toto.txt |awk ' $1 != D { print ; D = $1 }' | sort -nk2 | awk ' $2 != F { print ; F = $2 }'
    D pour Debut ( start ) et F pour ...

    Edit: /!\ le cas totalement inclus (25 31 5 ) fait une ligne distincte
    Edit2: il manquait le k2 pour des jeux de test plus variés

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 636
    Par défaut
    une solution, copiée sur celle de Jean.Cri1, sans awk :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    sort -rn -k1 -k3 fichier | sort -nu -k1 | sort -nu -k2,2
    10      30      20
    24      35      11
    40      68      28
    ...
    ?
    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  15. #15
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2006
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2006
    Messages : 247
    Billets dans le blog
    1
    Par défaut bien joué
    je dirais meme plus
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sort -nr toto.txt |sort -nu |sort -nu -k2
    la seule chose qui me gene c'est de considerer implicitement que le -nu (-kx ) garde la premiere occurence dans l'ordre ou le fichier est soumis,
    car ca ne me parait pas explicite dans le man.

    Pour les cas totalement inclus je crois qu'on ne coupera pas a une moulinette.

  16. #16
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 814
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 814
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Jean.Cri1 Voir le message
    je dirais meme plus
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sort -nr toto.txt |sort -nu |sort -nu -k2
    la seule chose qui me gene c'est de considerer implicitement que le -nu (-kx ) garde la premiere occurence dans l'ordre ou le fichier est soumis,
    car ca ne me parait pas explicite dans le man.
    Salut
    On appelle cela "stabilité" d'un tri: c'est le fait de garantir (stable) ou pas (instable) que 2 occurences à clefs égales resteront en sortie dans le même ordre qu'à l'entrée

    Normalement tu as l'option "-s" ou "--stable" de sort qui t'assure cette particularité => http://unixhelp.ed.ac.uk/CGI/man-cgi?sort
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  17. #17
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2006
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2006
    Messages : 247
    Billets dans le blog
    1
    Par défaut
    merci

Discussions similaires

  1. [StAX] Lecture et modification d'un fichier XML
    Par Thewil dans le forum Format d'échange (XML, JSON...)
    Réponses: 4
    Dernier message: 08/09/2011, 13h27
  2. Comparaison dans un fichier en cours de lecture
    Par CrissCross51 dans le forum Général Python
    Réponses: 3
    Dernier message: 11/04/2011, 09h04
  3. Réponses: 7
    Dernier message: 17/08/2010, 21h36
  4. Lecture et modification d'un fichier
    Par walacouper dans le forum z/OS
    Réponses: 1
    Dernier message: 27/05/2009, 23h58
  5. Réponses: 50
    Dernier message: 19/10/2007, 23h38

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