gratifiant > linux.debian.user.french

Marc Chantreux (30/06/2019, 00h40)
salut à tous,

j'aimerais beaucoup pouvoir utiliser find pour filtrer une liste de
chemins selon des critères de recherche. par exemple:

dpkg -L vim | find - -type f

ça n'est malheureusement pas possible. il existe de multiples
alternatives

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

mais c'est chiant à écrire et pas super efficace sur de grosses listes

une commande | xargs -I% find % -prune -type f

qui va lancer 1 find par ligne :(

une commande | xargs -J% find % -prune -type f

qui marche sur les *BSD mais pas avec GNU xargs

et finalement ma préférée sous linux

une commande | perl -lne 'print if -f'

qui me fait degainer perl pour un truc aussi simple.

est ce que quelqu'un aurait une solution simple, efficace et qui marche
sous linux?

cordialement,
marc
Francois Lafont (30/06/2019, 13h50)
Bonjour,

On 6/30/19 12:03 AM, Marc Chantreux wrote:

> j'aimerais beaucoup pouvoir utiliser find pour filtrer une liste de
> chemins selon des critères de recherche. par exemple:
> dpkg -L vim | find - -type f
> ça n'est malheureusement pas possible. il existe de multiples
> alternatives
> une commande | while read p; do
> test -f $p && echo $p
> done
> mais c'est chiant à écrire


Je te l'accorde...

> 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. Du coup, sauf erreur, il n'y a pas de
fork sur la partie droite du pipe et j'aurais donc dis que ça doit être
justement plutôt efficace sur de grosses listes. Je me trompe ?

Personnellement, c'est la commande que j'aurais utilisée.
Marc Chantreux (30/06/2019, 22h30)
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 '
Discussions similaires