Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Notion de "flux" et "pipe" en Perl

10 réponses
Avatar
Laurent
Salut,

Débutant depuis peu j'ai l'impression que Perl ne donne pas accès à la
logique de flux qu'on trouve dans le shell unix, je me sens par exemple
obligé de stocker les résultats intermédiaires avant de pouvoir travailler
en Perl dessus :

@liste_lignes = `ls *.txt | xargs grep toto`
foreach $ligne (@liste_lignes)
{
----
}

J'ai quelques cas où cette façon de faire nuit beaucoup aux performances,
prend pas mal de ressources , et par ailleurs ne permet pas d'avoir un
affichage progressif du résultat final (lorsque les opérations sont
longues). Est-ce la seule façon de s'y prendre ?

Merci

10 réponses

Avatar
Scetbon Cyril
Laurent wrote:
Salut,

Débutant depuis peu j'ai l'impression que Perl ne donne pas accès à la
logique de flux qu'on trouve dans le shell unix, je me sens par exemple
obligé de stocker les résultats intermédiaires avant de pouvoir travailler
en Perl dessus :

@liste_lignes = `ls *.txt | xargs grep toto`
foreach $ligne (@liste_lignes)
{
----
}
open(CMD,"ls *.txt | xargs grep toto|") || die $!;

while($line=<CMD>)
{
......
}
close(CMD) || warn $!;

J'ai quelques cas où cette façon de faire nuit beaucoup aux performances,
prend pas mal de ressources , et par ailleurs ne permet pas d'avoir un
affichage progressif du résultat final (lorsque les opérations sont
longues). Est-ce la seule façon de s'y prendre ?

Merci




Avatar
Benoit Izac
Bonjour,

le 01/04/2004 à 08:30, Laurent a écrit
dans le message <c4gcug$rsn$ :

Débutant depuis peu j'ai l'impression que Perl ne donne pas accès à la
logique de flux qu'on trouve dans le shell unix, je me sens par
exemple obligé de stocker les résultats intermédiaires avant de
pouvoir travailler en Perl dessus :

@liste_lignes = `ls *.txt | xargs grep toto`
^

Il manque un `;' ici.
foreach $ligne (@liste_lignes)
{
----
}


En shell, pas besoin de faire `ls *.txt | xargs grep toto', un simple
`grep toto *.txt' suffit.

Ensuite je ne comprends pas `je me sens par exemple obligé de stocker
les résultats intermédiaires avant de pouvoir travailler en Perl
dessus' :
foreach $line (`grep toto *.txt`) { }
ne fonctionne pas chez toi ?

Maintenant, si tu veux éviter de passer par le shell, tu peux faire tout
ça directement avec Perl : chercher les fichiers dont le nom fini par
`.txt' et dans chaqu'un d'eux, pour chaque ligne, regarder si le motif
`toto' apparait.
Ce qui donne un truc comme :

#!/usr/bin/perl -w
use strict;
my $dir = ".";
my $motif = "toto";
opendir(DIR, $dir) or die "can't open $dir: $!";
my @txt_files = grep { /.txt$/ && -f "$dir/$_" } readdir(DIR);
closedir(DIR);
my @liste_lignes;
foreach my $file (@txt_files) {
open(FH, "<", $file) or warn "can't open $file: $!" and next;
while (<FH>) {
push(@liste_lignes, "$file:$_") if (m/$motif/);
}
close(FH);
}
print @liste_lignes;
__END__

A noter que contrairement à `grep toto *.txt', cette version prend en
compte les fichiers qui commencent par un point.

J'ai quelques cas où cette façon de faire nuit beaucoup aux
performances, prend pas mal de ressources , et par ailleurs ne permet
pas d'avoir un affichage progressif du résultat final (lorsque les
opérations sont longues). Est-ce la seule façon de s'y prendre ?


"There's More Than One Way To Do It" est la devise de Perl !

Si tu veux afficher les lignes au fur et à mesure, remplace
push(@liste_lignes, "$file:$_") if (m/$motif/);
par
print("$file:$_") if (m/$motif/);

si tu veux les traiter immédiatement, tu remplaces :
push(@liste_lignes, "$file:$_") if (m/$motif/);
par
if (m/$motif/) {
# traitement sur $_ (la ligne avec le motif)
}

--
Benoit Izac

Avatar
Laurent Wacrenier
Laurent écrit:
@liste_lignes = `ls *.txt | xargs grep toto`
foreach $ligne (@liste_lignes)
{
----
}


Pourquoi ne pas le faire en perl ?

for my $f (<*.txt>) {
open F, $f or next;
while(<F>) {
print "$f:$_" if /toto/;
}
}

Avatar
Laurent
Merci bien pour toutes ces idées, c'est très utile de voir des bons exemples
sur un problème concret. J'ai fait comme Cyril l'indiquait, et ça me donne
satisfaction, en plus je trouve ça assez élégant. Mais c'est vrai que
j'imaginais pas parcourir l'arborescence en Perl car mon cas concret doit
parcourir en réalité tout un arbre (pour simplifier j'avais donné cet
exemple un peu mal choisi `ls *.txt | xargs grep toto`).

Juste deux questions :
1 - le "$file:$_" dans print "$f:$_" if /toto/; ou bien push(@liste_lignes,
"$file:$_") if (m/$motif/); c'est juste pour afficher le nom du fichier
devant la ligne trouvée ?
2 - l'accès aux fichiers par Perl est-ce que ça implique des performances
dégradées par rapport à ce que fait le shell ?
Avatar
Benoit Izac
Bonjour,

le 01/04/2004 à 21:05, Laurent a écrit
dans le message <c4hp5c$6h2$ :

Merci bien pour toutes ces idées, c'est très utile de voir des bons
exemples sur un problème concret. J'ai fait comme Cyril l'indiquait,
et ça me donne satisfaction, en plus je trouve ça assez élégant. Mais
c'est vrai que j'imaginais pas parcourir l'arborescence en Perl car
mon cas concret doit parcourir en réalité tout un arbre (pour
simplifier j'avais donné cet exemple un peu mal choisi `ls *.txt |
xargs grep toto`).


Tu peux parfaitement parcourir une arborescence en Perl. Regarde le
module File::Find.

Juste deux questions :
1 - le "$file:$_" dans print "$f:$_" if /toto/; ou bien
push(@liste_lignes, "$file:$_") if (m/$motif/); c'est juste pour
afficher le nom du fichier devant la ligne trouvée ?


Oui, juste pour te donner une sortie équivalente à un grep sur de
multiples fichiers. Si tu fais `print if /toto/;' (dans l'exemple de
Laurent), ça t'affichera juste la ligne qui correspond au motif.

2 - l'accès aux fichiers par Perl est-ce que ça implique des
performances dégradées par rapport à ce que fait le shell ?


Tout dépend comment tu l'implémentes en shell et en Perl. Avec
l'implémentation la plus rapide dans les deux language, je ne sais pas.
Néamoins, extrait de find2perl(1) :
DESCRIPTION
find2perl is a little translator to convert find command lines to
equivalent Perl code. The resulting code is typically faster
than running find itself.

Donc...
--
Benoit Izac

Avatar
DominiX
"Laurent" a écrit dans le message de
news:c4gcug$rsn$
Salut,

Débutant depuis peu j'ai l'impression que Perl ne donne pas accès à la
logique de flux qu'on trouve dans le shell unix, je me sens par exemple
obligé de stocker les résultats intermédiaires avant de pouvoir travailler
en Perl dessus :

@liste_lignes = `ls *.txt | xargs grep toto`
foreach $ligne (@liste_lignes)
{
----
}

J'ai quelques cas où cette façon de faire nuit beaucoup aux performances,
prend pas mal de ressources , et par ailleurs ne permet pas d'avoir un
affichage progressif du résultat final (lorsque les opérations sont
longues). Est-ce la seule façon de s'y prendre ?

Merci




la question est bien debattue, si tu veux approfondir il y a un article
interressant de MDJ a http://perl.plover.com/Stream/

--
dominix

Avatar
Scetbon Cyril
Tout dépend comment tu l'implémentes en shell et en Perl. Avec
l'implémentation la plus rapide dans les deux language, je ne sais pas.
Néamoins, extrait de find2perl(1) :
DESCRIPTION
find2perl is a little translator to convert find command lines to
equivalent Perl code. The resulting code is typically faster
than running find itself.

bizarre:

un petit test rapide me dit le contraire:
find2perl -name "*.mp3" -print > toto.pl
time perl toto.pl

0.31user 0.07system 0:00.77elapsed 49%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (433major+724minor)pagefaults 0swaps

time find . -name "*.mp3"

0.04user 0.04system 0:00.15elapsed 50%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (140major+140minor)pagefaults 0swaps

Avatar
Jean-Michel Grimaldi
On Thu, 01 Apr 2004 14:30:53 +0200, Benoit Izac wrote:
opendir(DIR, $dir) or die "can't open $dir: $!"; my @txt_files = grep {
/.txt$/ && -f "$dir/$_" } readdir(DIR); closedir(DIR);


glob est ton ami.

open(FH, "<", $file) or warn "can't open $file: $!" and next;


$! est déjà suffisamment explicite ; warn $! suffira donc, et die sera
plus approprié.

--
Jihem

Avatar
DominiX
ici même:c4jhae$,
Scetbon Cyril a écrit
find2perl is a little translator to convert find command
lines to equivalent Perl code. The resulting code is
typically faster than running find itself.

bizarre:

un petit test rapide me dit le contraire:
find2perl -name "*.mp3" -print > toto.pl
time perl toto.pl

0.31user 0.07system 0:00.77elapsed 49%CPU (0avgtext+0avgdata
0maxresident)k 0inputs+0outputs (433major+724minor)pagefaults 0swaps

time find . -name "*.mp3"

0.04user 0.04system 0:00.15elapsed 50%CPU (0avgtext+0avgdata
0maxresident)k 0inputs+0outputs (140major+140minor)pagefaults 0swaps


c'est parce que le resultat est deja dans le cache lor de la deuxieme
recherche. essaye dans l'autre sens tu vera bien si c'est ça.

find . ...
perl toto.pl

--
dominix


Avatar
Scetbon Cyril
time find . -name "*.mp3"
0.08user 0.01system 0:00.16elapsed 53%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (140major+140minor)pagefaults 0swaps

time perl toto.pl
0.35user 0.04system 0:00.78elapsed 49%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (433major+724minor)pagefaults 0swaps


Même chose après plusieurs essais.

DominiX wrote:
ici même:c4jhae$,
Scetbon Cyril a écrit

find2perl is a little translator to convert find command
lines to equivalent Perl code. The resulting code is
typically faster than running find itself.



bizarre:
un petit test rapide me dit le contraire:
find2perl -name "*.mp3" -print > toto.pl
time perl toto.pl

0.31user 0.07system 0:00.77elapsed 49%CPU (0avgtext+0avgdata
0maxresident)k 0inputs+0outputs (433major+724minor)pagefaults 0swaps

time find . -name "*.mp3"

0.04user 0.04system 0:00.15elapsed 50%CPU (0avgtext+0avgdata
0maxresident)k 0inputs+0outputs (140major+140minor)pagefaults 0swaps



c'est parce que le resultat est deja dans le cache lor de la deuxieme
recherche. essaye dans l'autre sens tu vera bien si c'est ça.

find . ...
perl toto.pl