#1 Le 02/06/2012, à 13: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 :
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, à 14: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, à 14:45)
Hors ligne
#3 Le 02/06/2012, à 14: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, à 21:10)
Hors ligne
#4 Le 02/06/2012, à 14:45
- Baronsed
Re : aide pour script en bash (commande grep)
Tu fais des bases de données en simples fichiers ?
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, à 17: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, à 18:58
- Evanescence
Re : aide pour script en bash (commande grep)
Merci pour vos contributions, je vais essayer ce que vous m'avez décrit
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
Dernière modification par Evanescence (Le 02/06/2012, à 19:55)
Hors ligne
#7 Le 02/06/2012, à 20: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, à 20:07)
Hors ligne
#8 Le 02/06/2012, à 20: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, à 21:51
- Baronsed
Re : aide pour script en bash (commande grep)
Je réfléchis à une solution à partir de :
sed -n '$a, $b p' <fichier>
où 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, à 21:55)
Hors ligne
#10 Le 02/06/2012, à 22: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
Dernière modification par Baronsed (Le 02/06/2012, à 22:55)
Hors ligne
#11 Le 03/06/2012, à 11: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
Hors ligne
#12 Le 03/06/2012, à 12: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, à 12:14)
Hors ligne
#13 Le 03/06/2012, à 12:09
- credenhill
Re : aide pour script en bash (commande grep)
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, à 12: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