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 :

Extraire des noms de fichiers d'un log - amélioration commande


Sujet :

Shell et commandes GNU

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti Avatar de novae84
    Homme Profil pro
    Etudiant.
    Inscrit en
    Juin 2022
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yonne (Bourgogne)

    Informations professionnelles :
    Activité : Etudiant.

    Informations forums :
    Inscription : Juin 2022
    Messages : 37
    Par défaut Extraire des noms de fichiers d'un log - amélioration commande
    Bonjour à tous,

    Je cherche à extraire une liste de tous les fichiers .js, mentionnés dans un fichier acces_log.txt

    La sortie ne doit pas :
    - Inclure le chemin d'accès complet, elle doit lister uniquement le nom du fichier .js

    La liste obtenue doit :
    - Être triée par ordre alphabétique
    - Ne faire apparaître chaque fichier qu'une fois

    Pour cela, j'ai fait la commande suivante, qui fonctionne bien.
    cat access_log.txt | grep '\.js ' | awk '{print $7}'| rev | cut -d '/' -f '1' | rev | sort -d | uniq.
    Toutefois j'aimerais l'améliorer si cela est possible car je ne la trouve pas très "clean".

    La première partie de la commande,
    cat access_log.txt | grep '\.js ' | awk '{print $7}'.
    Affiche la sortie suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    [...]
    /components/com_phocagallery/assets/js/shadowbox/src/lang/shadowbox-en.js
    /media/system/js/caption.js
    /templates/jp_hotel/js/moomenu.js
    /modules/mod_bowslideshow/tmpl/js/sliderman.1.3.0.js
    /media/system/js/mootools.js
    /media/system/js/caption.js
    [...]
    J'ai donc voulu utiliser cut avec le délimiteur / pour retirer les chemin d'accès au fichier.
    Sauf que certains fichiers sont à la racine, d'autre nécessitent de rentrer dans un, deux ou trois dossiers en amont.
    Du coup, je ne peux pas dire à cut le nombre de champs -f qu'il doit tronquer (à partir du début de la ligne).

    Pour cette raison, j'ai utilisé rev pour inverser la sortie, j'ai ensuite indiqué à cut de tronquer le premier champ sur lequel il tombe, puis j'ai de nouveau utilisé rev pour que la sortie soit lisible par un humain.

    Ca marche, mais je trouve que cela fait un peu bricolage.
    Est-ce qu'il ne serait pas possible d'indiquer à cut de se caler sur le premier délimiteur /, mais en partant de la fin de la ligne et non du début ?

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

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

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    grep -o '[^/ ]*\.js' access_log.txt | sort -u

  3. #3
    Membre averti Avatar de novae84
    Homme Profil pro
    Etudiant.
    Inscrit en
    Juin 2022
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yonne (Bourgogne)

    Informations professionnelles :
    Activité : Etudiant.

    Informations forums :
    Inscription : Juin 2022
    Messages : 37
    Par défaut
    Citation Envoyé par Flodelarab Voir le message
    Bonjour

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    grep -o '[^/ ]*\.js' access_log.txt | sort -u
    Bon et bien vu comme cela..

    Je maîtrise encore assez mal les regex, j'ai bien essayé de bricoler quelque chose dans ce sens mais sans succès.
    Du coup je me retrouve avec une commande à rallonge inutilement.

    Merci beaucoup pour l'astuce.

  4. #4
    Expert confirmé Avatar de papajoker
    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2013
    Messages
    2 324
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nièvre (Bourgogne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2013
    Messages : 2 324
    Par défaut
    Citation Envoyé par novae84 Voir le message
    Je maîtrise encore assez mal les regex, j'ai bien essayé de bricoler quelque chose dans ce sens mais sans succès.
    Du coup je me retrouve avec une commande à rallonge inutilement.
    les regex ont bon dos

    La première partie de la commande,
    cat access_log.txt | grep '\.js ' | awk '{print $7}'.
    ici, c'est juste une méconnaissance des commandes ...
    awk peut prendre un fichier en paramètre et ... awk supporte les regex en filtre !

    awk '/mon_reg/ {print x}' access_log.txt va donc faire le même en beaucoup plus léger

    Même chose avec cat access_log.txt | grep ...

  5. #5
    Membre averti Avatar de novae84
    Homme Profil pro
    Etudiant.
    Inscrit en
    Juin 2022
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yonne (Bourgogne)

    Informations professionnelles :
    Activité : Etudiant.

    Informations forums :
    Inscription : Juin 2022
    Messages : 37
    Par défaut
    Citation Envoyé par papajoker Voir le message
    les regex ont bon dos


    ici, c'est juste une méconnaissance des commandes ...
    awk peut prendre un fichier en paramètre et ... awk supporte les regex en filtre !

    awk '/mon_reg/ {print x}' access_log.txt va donc faire le même en beaucoup plus léger

    Même chose avec cat access_log.txt | grep ...
    J'avoue .. je ne suis pas du tout familier avec awk non plus.

    J'ai essayé ta commande et effectivement cela fonctionne bien. Je te remercie ! : )

    Par curiosité, j'ai voulu pousser un peu la chose pour obtenir le même résultat que grep -o '[^/ ]*\.js' access_log.txt | sort (juste le nom des fichiers sans le chemin d'accès donc) mais en le faisant juste avec awk cette fois.

    La manière la plus simple que j'ai trouvé est celle-ci :
    awk '{ if (match($0,/[^/ ]*\.js/,m)) print m[0] }' access_log.txt | sort -u.


    Est-ce le bon raisonnement, ou bien il y a plus simple ? (En utilisant juste awk)

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 294
    Par défaut
    • Pas mal cette commande awk.
    • Elle ne marche bien que s'il n'y a qu'un seul fichier dans une ligne.
    • Oui, on peut tout faire avec awk. Il ne reste plus qu'à mettre dans un tableau associatif (qui enlèvera les doublons, de fait) et le trier.
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
       awk '{ if (match($0,/[^\/ ]*\.js/,m)) tab[m[0]]++;} END{n=asorti(tab,tri); for (i=1;i<=n;i++) print tri[i];}' access_log.txt
    • Je souligne une nuance qui a pu passer inaperçu : sort | uniq ne sert à rien puisqu'on peut sort -u, sauf dans le cas où l'on compte.

  7. #7
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 850
    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 850
    Billets dans le blog
    1
    Par défaut
    Bonjour

    Citation Envoyé par novae84 Voir le message
    J'ai donc voulu utiliser cut avec le délimiteur / pour retirer les chemin d'accès au fichier.
    Sauf que certains fichiers sont à la racine, d'autre nécessitent de rentrer dans un, deux ou trois dossiers en amont.
    ...
    Est-ce qu'il ne serait pas possible d'indiquer à cut de se caler sur le premier délimiteur /, mais en partant de la fin de la ligne et non du début ?
    Et pourquoi tu ne demandes pas ça directement à awk qui, lui, sait compter les champs ???
    grep '\.js ' access_log.txt | awk '{print $7}'| awk -F/ '{print $NF}' |sort -ud.

    Sinon t'as aussi basename qui me semble être LA commande dédiée à ce travail de retirer les chemins d'accès au fichier
    basename -a $(grep '\.js ' access_log.txt | awk '{print $7}') |sort -ud, quitte à le passer par xargs si faire bouffer autant d'arguments à la commande est trop important => grep '\.js ' access_log.txt | xargs -i basename {} |sort -ud.

    Citation Envoyé par novae84 Voir le message
    Est-ce le bon raisonnement, ou bien il y a plus simple ? (En utilisant juste awk)
    Déjà la base c'est moins il y a de commande, mieux cela vaut. Ben oui, c'est sympa de jouer avec les pipes, ça montre qu'on a bien compris le mécanisme et qu'on jongle avec "à l'aise" (et je te renverse pour avoir le nom au début, et je te re-renverse pour remettre le nom à la fin) mais faut pas oublier que chaque pipe génère un processus.

    Ensuite il faut essayer de trouver les commandes les plus économes (ça c'est pour le temps de chargement et de traitement). awk est un gros truc donc on ne doit l'invoquer que si c'est absolument nécessaire. Je ne connais pas le fichier de départ (je n'ai pu partir que depuis ton exemple qui est issu de grep |awk...) donc comment est-il ? S'il est bien formaté, avec un seul séparateur entre chaque champ, tu peux alors remplacer awk '{print $7}' par cut -f7 (en y rajoutant éventuellement -d' ' si comme je le pense le délimiteur est l'espace).
    Mais si awk est vraiment nécessaire, alors autant essayer de lui en faire faire le plus possible, après-tout il est fait pour ça puisqu'il est programmable.

    Citation Envoyé par Flodelarab Voir le message
    Je souligne une nuance qui a pu passer inaperçu : sort | uniq ne sert à rien puisqu'on peut sort -u sauf dans le cas où l'on compte
    Oui, je l'avais vue aussi. J'en profite donc pour souligner une nuance qui a pu passer inaperçu: cat access_log.txt |grep ... ne sert à rien puisque l'on peut grep ... access_log.txt sauf dans le cas où... ah ben non, sauf dans aucun cas du tout en fait, cat access_log.txt |grep ... ne sert définitivement à rien
    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]

  8. #8
    Membre averti Avatar de novae84
    Homme Profil pro
    Etudiant.
    Inscrit en
    Juin 2022
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yonne (Bourgogne)

    Informations professionnelles :
    Activité : Etudiant.

    Informations forums :
    Inscription : Juin 2022
    Messages : 37
    Par défaut
    Je vous remercie pour vos retours.

    Ce que j'en retiens c'est qu'il faut surtout que j'essaie de connaître les commandes plus en profondeur, pour éviter de cumuler les pipes. Et rendre cela plus lisible et optimisé, aussi.

    Actuellement je suis une formation en ligne, mais étant donné qu'elle est orienté sur le pentest, elle est très généraliste.
    Beaucoup de commandes sont abordées, à juste titre. Mais les exemples qui sont donnés s'orientent beaucoup sur des cumuls de commandes différentes à l'aide de pipes, plutôt que sur leur maîtrise plus profonde.

    Il faut donc que j'essaie de sortir de "leur" logique un peu "touche à tout" et qui marche, mais qui n'est pas très optimisée.

    Les précisions faites ici sur awk me seront très utiles notamment.
    J'ai bien tenté d'éplucher la doc de awk, mais étant donné la richesse de la commande, ou plutôt du langage, il faut que je me bloque quelques jours dédiés à cela.

    Merci encore pour votre aide,

  9. #9
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 850
    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 850
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par novae84 Voir le message
    Ce que j'en retiens c'est qu'il faut surtout que j'essaie de connaître les commandes plus en profondeur
    Oui ça c'est bien. Car il ne faut pas oublier une chose, les commandes Unix, pour une grande majorité, sont prévues pour ne faire qu'un seul truc mais le faire bien. Donc plus tu en connaitras plus tu pourras élargir tes possibilités d'action.

    Citation Envoyé par novae84 Voir le message
    pour éviter de cumuler les pipes.
    Attention, faut pas non plus tomber dans l'excès inverse. Si tu as besoin de truc |chose n'aies pas peur de le faire (je me souviens une fois, pour convertir un csv en fichier ldap, je suis passé par 7 pipes d'affilée). Le truc c'est d'éviter les inutilités telles que cat ... |grep ou sort |uniq.

    Citation Envoyé par novae84 Voir le message
    Et rendre cela plus lisible
    Pour la lisibilité, t'as la possibilité d'écrire sur n lignes.
    Exemple commande1 |commande2 |commande3 |commande4 |commande5 |commande6 |commande7 se lira mieux ainsi
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    commande1\
    	|commande2\
    	|commande3\
    	|commande4\
    	|commande5\
    	|commande6\
    	|commande7
    Hé oui, le backslash dont on a beaucoup parlé lors de ton super find et qui, comme je l'ai dit, sert à inhiber l'action spécifique du caractère qui le suit, sert donc là encore à inhiber l'action spécifique du caractère qui le suit.
    Ici ce caractère étant <return> terminant la ligne, ce caractère <return> signifiant "action". Là il est inhibé donc il ne signifie plus "action" mais juste... rien du tout.
    Et (petit bonus) ça permet de rajouter ou enlever plus facilement des commandes utiles/inutiles...
    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]

  10. #10
    Membre averti Avatar de novae84
    Homme Profil pro
    Etudiant.
    Inscrit en
    Juin 2022
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yonne (Bourgogne)

    Informations professionnelles :
    Activité : Etudiant.

    Informations forums :
    Inscription : Juin 2022
    Messages : 37
    Par défaut
    Citation Envoyé par Sve@r Voir le message

    Attention, faut pas non plus tomber dans l'excès inverse. Si tu as besoin de truc |chose n'aies pas peur de le faire (je me souviens une fois, pour convertir un csv en fichier ldap, je suis passé par 7 pipes d'affilée). Le truc c'est d'éviter les inutilités telles que cat ... |grep ou sort |uniq.
    C'est bien noté, d'autant que pour l'accès au fichier cela est souvent prévu dans la commande, du coup je vais éviter ce genre de bricolages à l'avenir.
    Et pour sort | uniq .. je vais éviter aussi.

    Citation Envoyé par Sve@r Voir le message
    Pour la lisibilité, t'as la possibilité d'écrire sur n lignes.
    Exemple commande1 |commande2 |commande3 |commande4 |commande5 |commande6 |commande7 se lira mieux ainsi
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    commande1\
    	|commande2\
    	|commande3\
    	|commande4\
    	|commande5\
    	|commande6\
    	|commande7
    Hé oui, le backslash dont on a beaucoup parlé lors de ton super find et qui, comme je l'ai dit, sert à inhiber l'action spécifique du caractère qui le suit, sert donc là encore à inhiber l'action spécifique du caractère qui le suit.
    Ici ce caractère étant <return> terminant la ligne, ce caractère <return> signifiant "action". Là il est inhibé donc il ne signifie plus "action" mais juste... rien du tout.
    Et (petit bonus) ça permet de rajouter ou enlever plus facilement des commandes utiles/inutiles...
    C'est une très bonne astuce. Il est vrai que depuis notre précédent échange je l’utilise assez souvent à présent ce fameux "\".

    Je pense que je vais formater mes "grandes" commandes ainsi à l'avenir.
    En ayant plusieurs lignes en visu, je suis un peu moins embrouillé. J'arrive plus facilement à me dire "attention, est-ce que tu ne peux pas supprimer une de ces ligne en intégrant son contenu dans une autre commande déjà présente."

    Merci encore à tous pour les tuyaux, c'est très enrichissant.

  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 Sve@r Voir le message
    Pour la lisibilité, t'as la possibilité d'écrire sur n lignes.
    Exemple commande1 |commande2 |commande3 |commande4 |commande5 |commande6 |commande7 se lira mieux ainsi
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    commande1\
    	|commande2\
    	|commande3\
    	|commande4\
    	|commande5\
    	|commande6\
    	|commande7
    Je suis d'accord et j'aime bien utiliser le backslash pour la lisibilité.

    Quelqu'un sait-il si on peut mettre des commentaires à l'intérieur d'une telle structure ?

    Car ceci a la fâcheuse tendance à ne pas bien marcher :
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # ATTENTION: NE PAS FAIRE CECI:
    commande1\
    	# La commande1 sert à faire l'étape 1, avec ou sans \
    	# puis on passe à l'étape 2 comme ceci:
    	|commande2\
    	# Et maintenant l'étape 3
    	|commande3\
    	# etc.
    	|commande4\
    	|commande5\
    	|commande6\
    	|commande7

  12. #12
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 850
    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 850
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par jack-ft Voir le message
    Quelqu'un sait-il si on peut mettre des commentaires à l'intérieur d'une telle structure ?
    On peut pas. Faut bien comprendre que ce n'est pas vraiment une structure. Même si tu mets ça sur n lignes, le shell lui ne voit qu'une seule unique instruction terminée par un <return> pour la valider (le backslash des autres lignes demandant à ne pas traiter spécifquement les <return> qui terminent chacune, c'est comme si ces <return> n'existaient pas ; ou plus exactement comme s'ils représentaient un simple espace).

    Citation Envoyé par jack-ft Voir le message
    Car ceci a la fâcheuse tendance à ne pas bien marcher
    Hé oui. Dès que le "#" apparait, tout ce qui suit est ignoré jusqu'au <return> final (encore une fos les <return> intermédiaires ne sont pas traités).

    Ce que je peux proposer (oui ce n'est qu'un ersatz mais je vois pas d'autre solution)...
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # Le truc va être traité de cette façon
    # - la commande 1 va me sortir XYZ
    # - la commande 2 va extraire ZYX
    # - la commande 3 va transformer ça en XX XY XZ YY YZ ZZ
    # - la commande 4 va tout renverser
    # - ...
    commande1\
    	|commande2\
    	|commande3\
    	|commande4\
    	|commande5\
    	|commande6\
    	|commande7
    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]

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 09/10/2009, 09h44
  2. Récupérer des noms de fichiers dans une table ?
    Par florus dans le forum Access
    Réponses: 5
    Dernier message: 25/03/2006, 17h34
  3. Supprimer les espaces des noms de fichier
    Par Cathy dans le forum Linux
    Réponses: 20
    Dernier message: 04/08/2005, 17h13
  4. récupérer des nom de fichiers en utilisant *.ext
    Par drinkmilk dans le forum ASP
    Réponses: 11
    Dernier message: 15/12/2004, 09h21
  5. Réponses: 4
    Dernier message: 10/10/2003, 18h04

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