Shell find vs. gfind for simple script

For use with mail/neomutt, I need a script that gives me all the directories starting with . in my ~/Maildir/, sorted alphabetically, each prefixed with a + and separated by a single space. The number of directories is about 300.

I've managed to do this with both the base find(1) as well as misc/findutils. However, both have a drawback: the base find is ridiculously slow at the job, and misc/findutils is a separate port I'm having to put up with just for this one script.

For find(1): find -s ~/Maildir/ -maxdepth 1 -type d -name ".*" -execdir echo -n " +{}" \; – takes about 230 milliseconds to run.

For misc/findutils: gfind ~/Maildir/ -maxdepth 1 -type d -name ".*" -printf +%f\\n | sort | paste -sd" " - – takes about 10 milliseconds to run.
(The detour through sort(1) and paste(1) is needed because GNU find can't do sorting.)

The script runs every time neomutt starts. That's not strictly necessary, but it's a precaution against other clients creating or renaming folders in the ~/Maildir/. I want to be sure that neomutt always polls the folders currently in existence, and not some stale dirlisting from the day before yesterday. It's not practical to call the script everytime a folder gets changed, because there's different clients on different machinves involved. Also, I don't know of an elegant way to monitor the directory for changes and update if a folder changes.

What would you do? Just suck it down and accept that GNU find is needed for the job? Learn to accept the quarter-second delay when opening mail? Something else?
 
There is a find alternative called 'fd' , it is in Freebsd repo but named 'fd-find', it is written in Rust and it is way faster than find (drawback: you can't do everything you could do with find itself).
I like to use it in my personal noob scripts because of its speed, but I don't know if you want to install something or if you would prefer a better 'script solution' which I honestly can't provide you regarding my level in coding.
 
  • Thanks
Reactions: mtu
I would use this quarter of a second to look outside at a bird in a tree or a to see if during that quarter of a second a beatitull women passes.
Or use the best tool for the job.
A lot depends on the output of :
Code:
find ./Maildir |wc -l
 
  • Thanks
Reactions: mtu
your problem is you exec echo a lot of times

find -s ~/Maildir/ -maxdepth 1 -type d -name ".*" |sed -e 's/^/+ /'|sort|xargs echo -n
find -s ~/Maildir/ -maxdepth 1 -type d -name ".*" |sed -e 's/^/+/'|sort|tr "\n" " "
 
  • Thanks
Reactions: mtu
The "execdir" causes find(1) to fork and exec for each matching entry. The "xargs" option is designed to work around this.
This is about 100 times faster on my vm (I created 1000 entries in ~/Maildir/):
Code:
time (find -s $HOME/Maildir/ -maxdepth 1 -type d -name ".*" | xargs | sed -e "s;$HOME/Maildir/;+;g")
 
Thank you all! I didn't know I could use xargs in this way. The key fact is buried deep in the xargs(1) manpage: "If utility is omitted, echo(1) is used." – and in fact, it's more like "echo -n", which is exactly what I need. Thanks! Now I can save many quarters of a second ;) (But I might still look outside at a tree sometimes, Alain De Vos!)
 
Back
Top