Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 02/06/2012, à 12:13

Evanescence

aide pour script en bash (commande grep)

Bonjour,

j'aimerais réaliser un script en bash pour faire la chose suivante : j'ai un fichier dans lequel il y a une liste d'auteurs et pour chaque auteur il y a une liste de ses livres et j'aimerais afficher la liste de livres correspondant à un certain auteur. Cela se présente de cette façon :

http://hpics.li/7b182e6

je me doute qu'il faut utiliser la commande grep mais je ne vois pas trop comment m'y prendre. La commande affiche les lignes contenant une certaine chaîne de caractères mais là c'est pas vraiment ce que je veux faire.

Hors ligne

#2 Le 02/06/2012, à 13:21

Baronsed

Re : aide pour script en bash (commande grep)

En une ligne :

sed -e 's/,\ /\t/' fichier | grep -w -A <nombre d'ouvrages> nom_auteur | cut -f 3

Avec sed, on remplace ", " par une tabulation pour uniformiser les délimiteurs de champs et pouvoir aisément récupérer le troisième un peu plus loin avec cut. Pour grep :

man grep

Inconvénient : il faut connaître le nombre d'ouvrages, ou trouver un meilleur délimiteur sur l'ensemble des lignes (grep le fait peut-être aussi).

Dernière modification par Baronsed (Le 02/06/2012, à 13:45)

Hors ligne

#3 Le 02/06/2012, à 13:35

pingouinux

Re : aide pour script en bash (commande grep)

Bonjour,
En python (à modifier si le format du fichier est un peu différent) :

$ cat fichier
Dupond , Pierre livre1
                livre2
                livre3
Dupont , Paul   Livre_1
                Livre_2
                Livre_3

$ cat livres_d_un_auteur.py
#! /usr/bin/python
# -*- coding: utf-8 -*-

import sys, re

rec_auteur=re.compile('(^[ \t]*(\w+)\s*,\s*(\w+)\s*(\w.*?)$(\n^[ \t]*\w.*?$)*)',re.M)
with open(sys.argv[1],'r') as f :
   ligs=f.read()
   for k in rec_auteur.findall(ligs) :
      if sys.argv[2]!=k[1] : continue
      print( "%-10s %-10s => %-s"%(k[1],k[2],k[3]) )
      for livre in k[0].split('\n')[1:] :
         print( "%24s %-s"%('',livre.strip()) )

$ ./livres_d_un_auteur.py fichier Dupont
Dupont     Paul       => Livre_1
                         Livre_2
                         Livre_3

Édité : Petite correction du script

Dernière modification par pingouinux (Le 02/06/2012, à 20:10)

Hors ligne

#4 Le 02/06/2012, à 13:45

Baronsed

Re : aide pour script en bash (commande grep)

Tu fais des bases de données en simples fichiers ? big_smile
Fais attention que chaque nom d'auteur soit unique (sinon, il faut un ID). Il serait préférable également d'ajouter l'option -w à grep (sinon, les ouvrages des auteurs dont le nom contient partiellement le nom d'un autre auteur seront compté aussi ; exemple : Pol et Pola). J'ai édité mon post.

Hors ligne

#5 Le 02/06/2012, à 16:17

credenhill

Re : aide pour script en bash (commande grep)

hello
en reprenant le fichier de pingouinux

$ awk -v n="Dupont" 'NF>2{x=0} $1 == n { print ; x=1 } x && NF<2' fichier
Dupont , Paul   Livre_1
                Livre_2
                Livre_3
$ awk -v n="Dupond" 'NF>2{x=0} $1 == n { print ; x=1 } x && NF<2' fichier
Dupond , Pierre livre1
                livre2
                livre3
$ 

Hors ligne

#6 Le 02/06/2012, à 17:58

Evanescence

Re : aide pour script en bash (commande grep)

Merci pour vos contributions, je vais essayer ce que vous m'avez décrit smile
Baronsed m'a indiqué une solution si on connaît le nombre d'ouvrages mais comment on fait si on le connaît pas ?
Non ce n'est pas moi qui l'ai faite cette base de données on l'a juste reprise sur un site wink

Dernière modification par Evanescence (Le 02/06/2012, à 18:55)

Hors ligne

#7 Le 02/06/2012, à 19:05

aduxas

Re : aide pour script en bash (commande grep)

J'étais parti sur le même chemin que Credenhill, mais il y a un petit problème:

x && NF<2

Qui dit que les titres occupent moins de deux champs?  Si chaque titre est précédé d'un tab, il suffit de définir le séparateur de champs comme virgule ou tab; sinon, je pense qu'il faut d'abord reformatter les titres (sed ou awk/gsub)

EDIT:  il peut y avoir des virgules dans le titre aussi.

Dernière modification par aduxas (Le 02/06/2012, à 19:07)

Hors ligne

#8 Le 02/06/2012, à 19:27

Evanescence

Re : aide pour script en bash (commande grep)

Pinguinux propose une solution en python mais comment faire la même chose en bash ?

Hors ligne

#9 Le 02/06/2012, à 20:51

Baronsed

Re : aide pour script en bash (commande grep)

Je réfléchis à une solution à partir de :

sed -n '$a, $b p' <fichier>

a serait la ligne contenant le nom - facile à obtenir à partir de

grep -nw <nom> <fichier> | cut -f 1 -d :

et b la première occurence d'une ligne commençant par autre chose qu'une tabulation (autrement dit le nom de l'auteur suivant) - en partant de a, bien sûr.
Mais j'ai du mal avec la négation de (début de ligne + tabulation).

Dernière modification par Baronsed (Le 02/06/2012, à 20:55)

Hors ligne

#10 Le 02/06/2012, à 21:53

Baronsed

Re : aide pour script en bash (commande grep)

Ça ne ressemble guère à ce que j'avais prévu, mais ça fonctionne en 5 lignes (résultat sur la sortie standard, à toi de rediriger après).

#!/bin/bash
#     $ ./books <datafile> <author> 

# nombre de lignes dans le fichier
lines=`wc -l $1 | cut -f 1 -d \ `

# on garde ce qui suit l'auteur
# et envoie dans un fichier temporaire
grep -w -A $lines $2 $1 > tmp

# on trouve le numéro 'a' de la ligne de l'auteur suivant
a=`sed -n '/^\t/! =' tmp | sed -n 2p`

# on garde le début jusqu'à 'a'
head -n $((a-1)) tmp | sed -e 's/,\ /\t/' | cut -f 3
rm tmp

C'est pas très beau ; il est probablement possible de faire plus élégant (Perl ?). Merci pour les révisions big_smile

Dernière modification par Baronsed (Le 02/06/2012, à 21:55)

Hors ligne

#11 Le 03/06/2012, à 10:41

Evanescence

Re : aide pour script en bash (commande grep)

Merci pour toutes vos contributions, après quelques essais et quelques modifications le script fonctionne big_smile

Hors ligne

#12 Le 03/06/2012, à 11:02

miniSeb

Re : aide pour script en bash (commande grep)

Pour répondre à #10, voici un petit truc en Perl. Quelques éléments supplémentaires aux autres scripts : case insensitive et gère l'homonymie (et accessoirement permet la recherche par prénom, mais je ne sais pas si c'est utile) :

# usage : perl script.pl fichier nom
open FILE, $ARGV[0] or die $!;
my $query = lc($ARGV[-1]);
for (<FILE>) {
  push(@lines,split("\n",$_));
}
for (@lines) {
  if (m/^[^\s]/) {
    $author = (split("\t",$_))[0];
    $book = (split("\t",$_))[1];
    $bbg{$author} = "\n\t".$book;
  }else {
    $book = $' if m/^\s+/;
    $bbg{$author} .= ";\n\t".$book;
  }
}
foreach (keys %bbg) {
  print $_.' : '.$bbg{$_}."\n" if m/$query/i;
}

Output :

$ cat file 
Dupont, Pierre    Livre1
        Livre2
        Livre3
        Livre4
Dupond, Paul    LivreA
        LivreB
        LivreC
        LivreD
Dupont, Jean    LivreA1
              LivreB2
$ perl script.pl file dupont
Dupont, Pierre : 
    Livre1;
    Livre2;
    Livre3;
    Livre4
Dupont, Jean : 
    LivreA1;
    LivreB2

Dernière modification par miniSeb (Le 03/06/2012, à 11:14)

Hors ligne

#13 Le 03/06/2012, à 11:09

credenhill

Re : aide pour script en bash (commande grep)

aduxas a écrit :

Qui dit que les titres occupent moins de deux champs?  .

effectivement

$ cat a5
Dupond , Pierre livre1
                livre2 a
                livre3 b
Dupont , Paul   Livre_1
                Livre_2 c d
                Livre_3,e,f
$ 
$ awk -v n="Dupond" '$0 ~ /^[^ \t]/ {x=0} $1 == n { print ; x=1 } x && $0 ~ /^[ \t]/' a5
Dupond , Pierre livre1
                livre2 a
                livre3 b
$ awk -v n="Dupont" '$0 ~ /^[^ \t]/ {x=0} $1 == n { print ; x=1 } x && $0 ~ /^[ \t]/' a5
Dupont , Paul   Livre_1
                Livre_2 c d
                Livre_3,e,f
$ 

Hors ligne

#14 Le 03/06/2012, à 11:36

aduxas

Re : aide pour script en bash (commande grep)

En effet, credenhill.  On peut probablement simplifier la partie "pattern".  Si en plus la virgule après l'auteur peut y être collée :

awk -v n="Dupond" '/^[^ \t]/ {x=0} $1~n { print ;x=1 } x && /^[ \t]/'

Hors ligne