Answers:
一种方法是利用ls
来为我们提供文件列表,但是我们希望确保此列表每行仅显示1个文件或目录。该-1
交换机会为我们做到这一点。
$ ls -1
dir1
dir2
dir3
fileA
fileB
fileC
在一个空目录中创建上述示例数据。
$ mkdir dir{1..3}
$ touch file{A..C}
检查:
$ ls
dir1 dir2 dir3 fileA fileB fileC
现在开始计数,您可以wc -l
用来计数与ls -1
输出中的文件或目录相对应的行数。
$ ls -1 | wc -l
6
(但是请注意,它不包含隐藏文件)
要计算文件或目录,您需要稍微更改策略。在这种情况下,我将使用ls -l
它,因为它显示的是目录和文件。
$ ls -l
total 12
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir1
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir2
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir3
-rw-rw-r-- 1 saml saml 0 Nov 16 09:49 fileA
-rw-rw-r-- 1 saml saml 0 Nov 16 09:49 fileB
-rw-rw-r-- 1 saml saml 0 Nov 16 09:49 fileC
然后,我们可以grep
像这样过滤出目录或非目录:
# directories
$ ls -l | grep "^d"
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir1
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir2
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir3
# regular files
$ ls -l | grep "^-"
-rw-rw-r-- 1 saml saml 0 Nov 16 09:49 fileA
-rw-rw-r-- 1 saml saml 0 Nov 16 09:49 fileB
-rw-rw-r-- 1 saml saml 0 Nov 16 09:49 fileC
现在,只需wc -l
再次使用即可计算以上内容:
# directories
$ ls -l | grep "^d" | wc -l
3
# regular files
$ ls -l | grep "^-" | wc -l
3
不过,您可以wc
完全避免,并使用grep
的-c
选项:
$ ls -l | grep -c '^d'
(同样,不包括隐藏文件。请注意,目录和常规文件是两种类型的文件。还有更多类似命名管道,符号链接,设备,套接字...)。
如果您需要递归查找文件和目录,/usr/bin
则可能需要完全改变策略,并使用另一个名为的工具find
。
$ find /usr/bin | wc -l
4632
(尽管以上/usr/bin
本身已包括在内)
我上面使用的相同技术可以用来ls
做类似的事情,但ls
通常不是解析输出的好工具。find
另一方面是为此目的而构建的,并且提供了开关来查找文件或目录。
# find files
$ find /usr/bin -type f
# find directories
$ find /usr/bin -type d
(请注意,这次find
包括隐藏文件(.
和除外..
))。
我从来没有想过为什么换行符是创建文件名或目录名时要使用的合法字符。因此,上面讨论的方法将使用wc
和ls
不会与之抗衡,因此请牢记这一点。
用换行符创建目录和文件名。
$ mkdir $'dir4\n5'
$ touch $'fileD\nE'
ls
正确显示它们:
$ ls -1
dir1
dir2
dir3
dir4?5
fileA
fileB
fileC
fileD?E
但是wc
将包含换行符的目录和文件计为2项,而不是一项。
$ ls -1 | wc -l
10
解决此问题的一种方法(如果使用GNU实现)find
是利用find
的功能来代替它找到的每个文件打印其他内容,然后对它们进行计数。
$ find . -printf . | wc -c
9
在这里,我们可以找到当前目录中的所有内容(除外..
),并.
为每个目录打印一个点(),然后使用wc
计数字节数而不是行数的能力对点进行计数wc -c
。
/usr/bin
的文件都将格式正确(并且也将不包含空格,所以从技术上讲您甚至都可以echo * | wc -w
),但值得注意的是,所有这些文件都会在包含换行符的文件名上中断。
ls -l
或ls -1
会打破b / c,我们正在计算行数,而不是文字!该find
可破,但同样,我们就指望行不言。
touch $'foo\nbar'
在一个空目录中,后跟您的命令之一(例如ls -1 | wc -l
)将报告两个文件而不是一个文件-因为该文件相对于两行wc
而言。除非ls
用其他字符替换换行符(我不认为这样做,但是现在我无法进行测试)。
wc -c
在计算期间时是否有问题?
如果要在某个目录下使用GNU递归分解每种文件的数量find
,可以执行以下操作:
find /some/dir/. ! -name . -printf '%y\n' | sort | uniq -c | sed '
s/f/regular files/;t
s/d/directories/;t
s/l/symbolic links/;t
s/s/Unix domain sockets/;t
s/b/block devices/;t
s/c/character devices/;t
s/p/FIFOs/;t
s/D/Doors/;t
s/n/network special files/;t
s/.$/others (&)/'
在/usr/bin
我的系统上,这给出了:
3727 regular files
710 symbolic links
开/dev
:
83 block devices
203 character devices
31 directories
426 symbolic links
1 FIFOs
1 Unix domain sockets
对于符号链接,如果您希望将它们视为它们指向的文件类型而不是symbolic links
,则可以将其更改为:
find /some/dir/. ! -name . -printf '%Y\n' | sort | uniq -c | sed '
s/f/regular files/;t
s/d/directories/;t
s/N/broken symbolic links/;t
s/s/Unix domain sockets/;t
s/b/block devices/;t
s/c/character devices/;t
s/p/FIFOs/;t
s/D/Doors/;t
s/n/network special files/;t
s/.$/others (&)/'
现在给我/usr/bin
:
1 directories
4434 regular files
2 broken symbolic links
(断开的符号链接是指向文件的符号链接,该符号链接find
无法确定类型,原因是该文件不存在,或者位于您无权访问的目录中,或者文件路径的解析中存在循环在我的情况下,符号链接到现在消失的文件的那两个)。
这些数都不.
及..
。如果您希望将它们包括在内(为什么?),find
除了假定每个目录都存在它们并系统地对它们进行计数,别无其他方法:
find /some/dir/. -printf '%y\n' \( -name . -printf 'd\n' -o \
-type d -printf 'd\nd\n' \) | sort | uniq -c | sed '
s/f/regular files/;t
s/d/directories/;t
s/l/symbolic links/;t
s/s/Unix domain sockets/;t
s/b/block devices/;t
s/c/character devices/;t
s/p/FIFOs/;t
s/D/Doors/;t
s/n/network special files/;t
s/.$/others (&)/'
然后给我/usr/bin
:
2 directories
3727 regular files
710 symbolic links
如果您无权访问GNU find
,则可以将第一个重写为:
find /some/dir/. ! -name . \( \
-type f -exec printf '%.0sregular files\n' {} + -o \
-type d -exec printf '%.0sdirectories\n' {} + -o \
-type l -exec printf '%.0ssymbolic links\n' {} + -o \
-type s -exec printf '%.0sUnix domain sockets\n' {} + -o \
-type b -exec printf '%.0sblock devices\n' {} + -o \
-type c -exec printf '%.0scharacter devices\n' {} + -o \
-type p -exec printf '%.0sFIFOs\n' {} + -o \
-exec printf '%.0sothers\n' {} + \) | sort | uniq -c
现在,严格来说,我们不是在计算文件,而是在目录条目。像这样的目录/usr/bin
通常具有指向同一文件的多个条目。例如,在这里,我有:
$ ls -lid /usr/bin/{nvi,nview,nex}
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nex
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nvi
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nview
这些是指向同一文件(带有inode 672252的3个目录条目)(又称文件名,也称为硬链接)。要计算文件而不是目录条目,并使用GNU find
和GNU uniq
(忽略.
和..
仍然是指向其他目录的硬链接的文件):
find /some/dir/. ! -name . -printf '%y\t%D:%i\n' |
sort -u |
cut -f1 |
uniq -c |
sed '
s/f/regular files/;t
s/d/directories/;t
s/l/symbolic links/;t
s/s/Unix domain sockets/;t
s/b/block devices/;t
s/c/character devices/;t
s/p/FIFOs/;t
s/d/Doors/;t
s/n/network special files/;t
s/.$/others (&)/'
在我的/usr/bin
,它给出:
3711 regular files
710 symbolic links
使用bash,无需外部工具。
cd dir/ || exit; shopt -s nullglob; shopt -s dotglob; count=(*); echo "${#count}"
在bash中,无需外部工具和递归。
shopt -s globstar; shopt -s dotglob
for dir in **/*/; do
unset d f
for files in "$dir"*; do
[[ -f $files ]] && ((++f))
[[ -d $files ]] && ((++d))
done;
printf '%s\n' "$dir - files: ${f:-0} - directories: ${d:-0}"
done
.
并且也不对..
条目进行计数。您可能要消除文件与常规文件的歧义。