What version of fd are you using?
[paste the output of fd --version here]
fd 8.1.1
Another in my series of "Let's replace find" tasks (while learning bash as well). This should be simple, but I'm missing it. To wit, on a cluster I'm on we have inode limits, thus when I get close I often run a script:
#!/bin/bash
for item in *
do
if [[ -d $item ]]
then
num=$(find $item | wc -l)
echo $num $item
fi
done
that counts up the files in a set of subdirs. So if I run that in a directory I get, say:
$ time files_per_directory
48779 CURRENT
48779 PREVIOUS
real 0m20.946s
user 0m0.300s
sys 0m0.788s
Now I can do this:
#!/bin/bash
for item in *
do
if [[ -d $item ]]
then
cd $item
num=$(fd --no-ignore-vcs | wc -l)
cd ..
echo $num $item
fi
done
which works and is fast:
$ time files_per_directory_fd
47666 CURRENT
47666 PREVIOUS
real 0m1.776s
user 0m1.048s
sys 0m1.024s
It just seems...clunky to me (not sure what files I might be missing, but close enough).
Is there a better/more elegant way of doing it that doesn't involve changing directories?
You can use fd . "$item" --no-ignore --hidden to avoid having to change directories, since the pattern "." will always match.
Another option is the --base-directory <path> argument.
If you want the whole script in a single command (who wouldn't? :smile:), you could run something like:
fd -d1 -td -x bash -c "echo -n '{} '; fd -HI --base-directory '{}' | wc -l"
Note that this is vulnerable to shell injection (if a directory name contains a single quote ') - which is why I would not recommend using this. Also, I don't really see a problem with your script. That's what bash scripts are made for. If you want to simplify it, you can replace the
for item in *
do
if [[ -d $item ]]
then
……
fi
done
part by
for dir in */
do
……
done
Also, If you really want to count files per directory, you would have to use --type file.
I'm not a huge fan of globs, and I realize this isn't fd (I'm using depth-pinning with find, not sure if there's something comparable in fd), but maybe it gives some ideas?
❯ find . | xargs file
.: directory
./d1: directory
./d1/f3: empty
./d1/f2: empty
./d1/f1: empty
./d3: directory
./d3/d4: directory
./d3/d4/f4: empty
./d3/d4/f5: empty
./d2: directory
./d2/f6: empty
❯ for d in $(find . -type d -mindepth 1); do echo "$d $(find $d -maxdepth 1 -type f | wc -l)"; done
./d1 3
./d3 0
./d3/d4 2
./d2 1
Closing this, as the question has been answered, IMO