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 :

Script pour scanner fichiers


Sujet :

Shell et commandes GNU

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    206
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 206
    Par défaut Script pour scanner fichiers
    Bonjour,
    voici mon problème.
    J'ai grossomodo 1 millions de fichiers disséminés une arborescence de dossier du type ./yyyy/mm/dd (année mois jour).
    La 3ème ligne du header de chacun de ces fichiers doit se terminer par la lettre K. Or, il est possible que pour certains d'entre eux (peu pour moi serait le mieux) la 3ème ligne ne se termine pas par cette lettre.
    Je voudrais donc écrire un script permettant de scanner l'intégralité des fichiers, de repérer ceux n'ayant pas la bonne 3ème ligne et de les copier dans un répertoire temporaire.
    Pouvez vous SVP m'aiguiller?
    Merci beaucoup

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

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

    tu rediriges la sortie de find vers le read d'une boucle while, dans laquelle tu extrais le dernier caractère de la troisième ligne du fichier en cours avec sed pour tester s'il vaut "K".
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  3. #3
    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
    Citation Envoyé par cpalperou Voir le message
    Bonjour,
    Je voudrais donc écrire un script permettant de scanner l'intégralité des fichiers, de repérer ceux n'ayant pas la bonne 3ème ligne et de les copier dans un répertoire temporaire.
    Pouvez vous SVP m'aiguiller?
    Merci beaucoup
    si c'est temporaire il est inutile de copier les fichiers tu fais une liste des fichiers dans /tmp/

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    find /chemin/de/base -type f -exec grep -l ".*..K$" {} \; > /tmp/toto
    ça donne une liste sous la forme :
    exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    sh-4.2$ touch {a,b,c,d,e,f,g,h,i,j}
    sh-4.2$ ls
    a  b  c  d  e  f  g  h  i  j
    sh-4.2$ echo "cvK" >k
    sh-4.2$ echo "cvK" >l
    sh-4.2$ find . -type f -exec grep -l ".*..K$" {} \; 
    ./l
    ./k
    sh-4.2$ rm [a-l]

    après il te reste plus qu'à relire ton fichier temporaire pour lancer un éventuel traitement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    while read
    do 
    #traitement de $REPLY
    done < /tmp/tonfichier_de_liste
    donc en une seule passe ça devient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    while read
    do 
    #traitement de $REPLY
    done < $( find /chemin/de/depart -type f -exec grep -l ".*..K$" {} \; 2> /dev/null )

  4. #4
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 103
    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 103
    Par défaut
    Citation Envoyé par frp31 Voir le message
    si c'est temporaire il est inutile de copier les fichiers tu fais une liste des fichiers dans /tmp/

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    find /chemin/de/base -type f -exec grep -l ".*..K$" {} \; > /tmp/toto
    ça marche, ça, pour tester si la 3ème ligne finit par K?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    find /chemin/de/base -type f -exec sh -c "head -3 {} | tail -1 | egrep -q -v 'K$' && echo {}" \; > /tmp/liste_fichiers.txt
    y a probablement plus rapide...

    Sinon, on peut aussi copier directement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    find /chemin/de/base -type f -exec sh -c "head -3 {} | tail -1 | egrep -q -v 'K$' && cp {} /le/repertoire" \;
    BUG: ça rend un faux-positif pour un fichier de moins de 3 lignes (donc 1 ou 2) dont la dernière ne se termine pas par K.

  5. #5
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    1 946
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 1 946
    Par défaut
    Citation Envoyé par jack-ft Voir le message
    Sinon, on peut aussi copier directement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    find /chemin/de/base -type f -exec sh -c "head -3 {} | tail -1 | egrep -q -v 'K$' && cp {} /le/repertoire" \;
    BUG: ça rend un faux-positif pour un fichier de moins de 3 lignes (donc 1 ou 2) dont la dernière ne se termine pas par K.
    Changer head -3 {} | tail -1 | par sed -n '3p' {} |

  6. #6
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 103
    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 103
    Par défaut
    Citation Envoyé par zipe31 Voir le message
    Changer head -3 {} | tail -1 | par sed -n '3p' {} |
    Ah ben ouais!
    Va vraiment falloir que je mette à sed...

  7. #7
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    1 946
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 1 946
    Par défaut
    Citation Envoyé par jack-ft Voir le message
    Ah ben ouais!
    Va vraiment falloir que je mette à sed...
    Et à awk

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    find /chemin/de/base -type f -exec  awk 'NR==3 && $NF =! /K$/ { print FILENAME }' {} \;
    PS. Je laisse le soin aux fortiches en awk de rajouter la commande qui va bien pour copier directement les fichiers dans /tmp... merci

  8. #8
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 103
    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 103
    Par défaut
    Citation Envoyé par zipe31 Voir le message
    Et à awk
    Ah ben non! awk, ça va! Je veux dire que je peux écrire un programme de plusieurs pages (c'est plus dur pour les programmes en 1 ligne et demi que nous pondent certains ici!), mais, au moins, je suis autonome... parce que pour sed, avec sa syntaxe, c'est une autre paire de manches (on dirait de l'APL... (pour moi!)).

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    206
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 206
    Par défaut
    Bonjour et merci pour vos réponses.
    J'ai donc essayé cette commande basée sur vos réponses:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    find ./ -type f -exec sh -c "sed -n '3p' {} | egrep -q -v 'K$' && cp {} /tmp/toto" \;
    Je dois scanner les répertoires /home/data/yyyy/mm/dd/ , je me suis donc mis sous /home/data/ et j'ai executée la commande.

    Si je comprends bien, je devrais avoir dans le fichier /tmp/toto les noms des fichiers dont la 3ème ligne se termine par K sous la forme /yyyy/mm/dd/filename . Est-ce correct?
    Or, mon fichier /tmp/toto contient un des fichiers de mon arborescence (pas son nom, le contenu de ce fichier).
    Je pense donc faire une bétise dans mon adaptation des commandes que vous me proposez.

    Autre détail d'importance (qui n'est donc pas un détail!), il ne s'agit pas du dernier caractère de la 3ème ligne mais de l'avant-avant-avant dernier.
    C'est à dire que la 3ème igne se termine soit par: soit par merci beaucoup

  10. #10
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    1 946
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 1 946
    Par défaut
    Citation Envoyé par cpalperou Voir le message
    Si je comprends bien, je devrais avoir dans le fichier /tmp/toto les noms des fichiers dont la 3ème ligne se termine par K sous la forme /yyyy/mm/dd/filename . Est-ce correct?
    Euh... non. Tu dois avoir le nom des fichiers dont la 3ème ligne NE se termine PAS par "K", selon ta demande initiale.

    Or, mon fichier /tmp/toto contient un des fichiers de mon arborescence (pas son nom, le contenu de ce fichier).
    Je pense donc faire une bétise dans mon adaptation des commandes que vous me proposez.
    Bizarre, parce que la même commande chez moi retourne bien le nom du fichier et non son contenu

    Autre détail d'importance (qui n'est donc pas un détail!), il ne s'agit pas du dernier caractère de la 3ème ligne mais de l'avant-avant-avant dernier.
    C'est à dire que la 3ème igne se termine soit par: soit par
    Il suffit de remplacer "K$" par "[JK]..$" dans le "grep".

    Voila un exemple chez moi...

    Le contenu de mon répertoire :
    Le contenu des fichiers (seuls f2 et f3 remplissent les conditions, à savoir le caractère J ou K en antépénultième place de la 3 ème ligne) :
    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
    $ head * | cat -A
    ==> f1 <==$
    1$
    2$
    3$
    4$
    5$
    6$
    7$
    $
    ==> f2 <==$
    1$
    2$
    3J  $
    4$
    5$
    6$
    7$
    $
    ==> f3 <==$
    1$
    2$
    3K  $
    4$
    5$
    6$
    7$
    $
    ==> f4 <==$
    1$
    2$
    3$
    4$
    5$
    6$
    7$
    $
    ==> f5 <==$
    1$
    2$
    3$
    4$
    5$
    6$
    7$
    La commande avec "sed" (je ne fais qu'afficher les fichiers avec la commande "echo") :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ find /home/jp/trash/ -type f -exec sh -c "sed -n '3p' {} | egrep -q -v '[JK]..$' && echo {}" \;
    /home/jp/trash/f5
    /home/jp/trash/f4
    /home/jp/trash/f1
    La même avec "awk :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ find /home/jp/trash/ -type f -exec awk 'NR==3 && $0 =! /[JK]..$/ { print FILENAME }' {} \;
    /home/jp/trash/f5
    /home/jp/trash/f4
    /home/jp/trash/f1

  11. #11
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 103
    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 103
    Par défaut
    Citation Envoyé par zipe31 Voir le message
    Bizarre, parce que la même commande chez moi retourne bien le nom du fichier et non son contenu
    àmha vous ne parlez pas du même script!
    Dans mon premier post, j'avais fourni les 2 versions:
    celle qui copie les noms dans un fichier (avec 'echo')
    et celle qui copie les fichiers dans un répertoire (avec 'cp').

  12. #12
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    1 946
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 1 946
    Par défaut
    Citation Envoyé par jack-ft Voir le message
    àmha vous ne parlez pas du même script!
    Dans mon premier post, j'avais fourni les 2 versions:
    celle qui copie les noms dans un fichier (avec 'echo')
    et celle qui copie les fichiers dans un répertoire (avec 'cp').
    Si si j'avais bien noté, je le dis d'ailleurs, je me cite "La commande avec "sed" (je ne fais qu'afficher les fichiers avec la commande "echo")", en sous-entendant par "fichiers" le nom des fichiers. C'était surtout pour bien voir ce que contenait les "{}"

    Mais bon, peut importe la commande (echo, cp, etc.) si le résultat était autre que le nom du fichier, echo l'afficherait et cp renverrait un message d'erreur, non ?

  13. #13
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 103
    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 103
    Par défaut
    Citation Envoyé par cpalperou Voir le message
    il ne s'agit pas du dernier caractère de la 3ème ligne mais de l'avant-avant-avant dernier.
    C'est à dire que la 3ème igne se termine soit par: soit par
    J'ai un peu de mal avec les spécifications incrémentales...

    Veux-tu dire que la 3ème ligne d'un quelconque fichier se termine TOUJOURS soit par '/J ' soit par '/K ' et que tu veux:
    déterminer lesquels se terminent par '/K '?
    ou lesquels NE se terminent PAS par '/K '?
    ou lesquels se terminent par '/J '?
    ou lesquels se terminent par '/J ' ou '/K '?
    ou lesquels ne se terminent ni par '/J ' ni par '/K '?
    ou lesquels se terminent à la fois par '/J ' et par '/K '?

    Rayez les mentions inutiles...

  14. #14
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    206
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 206
    Par défaut
    Bonjour,
    j'ai résolu mon problème avec la superbe commande ci-dessous. Elle marche très bien et est très rapide:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    while read f; do
      [ -z "$(grep "REF_DOC.*/K" <(head -4 $f))" ] && echo $f;
    done < <(find /home/20?? -type f) > /home/list.tmp.txt
    REF_DOC est un terme contenu aussi dans toutes les 3 ème lignes de mes fichiers.
    Merci à tous

  15. #15
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 103
    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 103
    Par défaut
    Citation Envoyé par cpalperou Voir le message
    Bonjour,
    j'ai résolu mon problème avec la superbe commande ci-dessous. Elle marche très bien et est très rapide:
    Probablement un poil plus rapide (en testant le status du grep et non la chaine retournée sur la stdout):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    while read f; do
      grep -q "REF_DOC.*/K" <(head -4 $f) || echo $f;
    done < <(find /home/20?? -type f) > /home/list.tmp.txt

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 664
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    find /home/20?? -type f -exec awk 'FNR==3 && ! /K$/{print > "/home/list.tmp.txt"}' {} \+
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

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

Discussions similaires

  1. Généraliser script pour plusieurs fichiers
    Par lovelace63 dans le forum Langage
    Réponses: 5
    Dernier message: 11/11/2012, 10h50
  2. script pour scanner
    Par a_allatiff dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 07/10/2010, 20h47
  3. Script pour modifier fichier "host"
    Par chuispasla dans le forum Scripts/Batch
    Réponses: 1
    Dernier message: 05/08/2009, 14h03
  4. script pour parsing fichier xml
    Par Melvine dans le forum Modules
    Réponses: 4
    Dernier message: 06/10/2006, 18h47
  5. script windows pour copier fichier
    Par sacan dans le forum Windows
    Réponses: 3
    Dernier message: 09/06/2006, 12h24

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