I need a script or command that prints a number of directories which name begins from "lib" in whole directory subtree. I was trying to do it using find, grep, and wc but can't scan all directories. How to do it?
4 Answers
find . -type d -name lib\* -exec echo x \; | wc -l
-
That does run one
echocommand in a new process for eachlib*directory though, which is not efficient.Stéphane Chazelas– Stéphane Chazelas2017-06-29 13:33:02 +00:00Commented Jun 29, 2017 at 13:33 -
I doubt there's any reason to use echo.
find . -type d -name lib\* -printf "%i\n" | wc -lshould be sufficient. Letfindhandle everything instead of calling extra process there.Sergiy Kolodyazhnyy– Sergiy Kolodyazhnyy2017-06-30 21:18:35 +00:00Commented Jun 30, 2017 at 21:18 -
@SergiyKolodyazhnyy -printf is gnu specificStéphane Chazelas– Stéphane Chazelas2017-06-30 22:06:44 +00:00Commented Jun 30, 2017 at 22:06
-
@StéphaneChazelas didn't know. Will rememberSergiy Kolodyazhnyy– Sergiy Kolodyazhnyy2017-06-30 22:10:53 +00:00Commented Jun 30, 2017 at 22:10
LC_ALL=C find .//. -name 'lib*' -type d | grep -c //
You can't use find . | wc -l as that wouldn't work properly if there are file paths with newline characters.
Without LC_ALL=C that could fail to count dir names that start with lib but where the rest of the name contains bytes that don't form valid characters.
With zsh:
(){echo $#} **/lib*(DN/)
-
1Neat trick with
.//....2017-06-29 13:33:54 +00:00Commented Jun 29, 2017 at 13:33 -
Wait, can you explain how does
.//.work ? I get the idea thatgrep -cshould be able to count lines starting with that pattern, but it seems like after./should only be filenames and yet there's another slash dot there, and it still works. How ?Sergiy Kolodyazhnyy– Sergiy Kolodyazhnyy2017-06-30 21:50:12 +00:00Commented Jun 30, 2017 at 21:50 -
@SergiyKolodyazhnyy
.is the current directory, which may also be spelled./. Slashes can be repeated, so.//is still the current directory, and.//.is the same as well (foo/.is always the same asfoo).findwill print its results relative to the root directory you specified, in this case like.//./libwhatever,.//./foo/bar/libsomething, etc.Tavian Barnes– Tavian Barnes2017-07-03 03:00:37 +00:00Commented Jul 3, 2017 at 3:00
Assuming all lib-directories have sane names with no newlines or other strange/exotic characters:
find / -type d -name "lib*" -print | wc -l
This assumes that you, by the "whole directory subtree", mean "anywhere". Change / into . to only count in the current directory or below.
The find command would find all directories (-type d) whose name start with lib (-name "lib*") and print these (-print).
The wc -l would count the number of lines in the output from find.
-
I'm not sure about BSD find, but at least with GNU find
-printis default behavior, so we could leave that off, no ? And as I commented on other answer, the strange/exotic filenames probably can be handled with-printf "%i\n"option insteadSergiy Kolodyazhnyy– Sergiy Kolodyazhnyy2017-06-30 21:53:30 +00:00Commented Jun 30, 2017 at 21:53
Here's a bash-only solution, using globstar shell option:
$ shopt -s globstar; c=0; for f in ** ; do echo "${f##*/}"; [[ "${f##*/}" =~ ^lib* ]] && [[ -d "$f" ]] && ((c++)); done ; echo $c
Or in script format for readability:
#!/usr/bin/env bash
shopt -s globstar
c=0
for f in **
do
echo "${f##*/}"
if [[ "${f##*/}" =~ ^lib* ]] && [[ -d "$f" ]]
then
((c++))
done
echo $c
globstar allows us to enable recursive globbing and via [[ with pattern matching and -d flag to check if that's a directory, we increment the counter variable $c, which we print at the end.