hello,

> >    une commande | while read p; do
> >      test -f $p && echo $p
> >    done

> > mais c'est chiant à écrire
> Je te l'accorde...

bon réellement j'ai dans mon .zshenv:

  '?-' () while {read it} {"$@" $it && print $it}

du coup en vrai j'écris

  une commande |\?- test -f

mais si j'écris un script pour les collègues, je me force à ne pas
utiliser ce genre de shortcuts

> > et pas super efficace sur de grosses listes

> ... tu es sûr de ça ? J'ai un doute, parce que "while" est un mot clé,
> "read" et "test" sont built-in.

d'experience, il n'y a pas photo: les filtres sont toujours plus
performants que les while loops.

d'un autre coté: j'ai acquis cette conviction il y a fort longtemps
(fin du millénaire dernier ) sans actualiser ni approffondir ...
alors j'ai fais un benchmark au doigt mouillé (le script ci-apres) qui
me permet de confirmer ...

sachant que:

* bash n'est pas présent dans le test parceque:
  * c'est un shell que je n'utilise pas
  * j'ai fais le test sur une box openbsd pour avoir xargs -J
* je n'ai même pas essayé avec xargs -I ... ce sera forcément tristoune
* zsh fait un bien mauvais score: je note mais ca n'est pas le sujet
  alors je n'ai pas cherché à savoir si c'était perfectible
* perl forever \o/

shell   user    kernel  elapsed
ksh     0.75s   0.57s   1.33s
zsh     2.77s   4.97s   7.73s
sh      0.80s   0.53s   1.33s
xargs   0.13s   0.61s   0.74s
perl    0.07s   0.37s   0.44s

le script en question:

  # creer un jeu de données

  find . >     sep---
  cat          sep---{,,,,,,,,,,,} > sep-0a
  tr '\n' '\0' < sep-0a > sep-00
  times=5

  # lire le jeu une premiere fois histoire d'etre fair play
  cat sep* > /dev/null

  # while loop
  script='
    while read it; do
      test -f "$it" && echo "$it"
    done > /dev/null
  '

  print shell user kernel elapsed

  for shell (ksh zsh sh) {
    TIMEFMT="$shell %U %S %E"
    < sep-0a time $shell -c $script
  }

  TIMEFMT="xargs %U %S %E"
  < sep-00 time sh -c 'xargs -0 -J %  find % -prune -type f > /dev/null 2>&1'

  TIMEFMT="perl %U %S %E"
  < sep-0a time sh -c ' perl -lne"print if -f" > /dev/null 2>&1 '

Répondre à