cas*_*ash 11 scripting find wc file-types
如何使用字计数器 ( wc) 和管道来计算目录中有多少文件或/usr/bin目录?
slm*_*slm 14
一种方法是利用 为ls我们提供文件列表,但我们希望保证该列表每行仅显示 1 个文件或目录。该-1交换机会为我们做到这一点。
$ ls -1
dir1
dir2
dir3
fileA
fileB
fileC
Run Code Online (Sandbox Code Playgroud)
在空目录中创建上述示例数据。
$ mkdir dir{1..3}
$ touch file{A..C}
Run Code Online (Sandbox Code Playgroud)
核实:
$ ls
dir1 dir2 dir3 fileA fileB fileC
Run Code Online (Sandbox Code Playgroud)
现在要计数,您可以使用wc -l来计算与ls -1输出中的文件或目录相对应的行数。
$ ls -1 | wc -l
6
Run Code Online (Sandbox Code Playgroud)
(但请注意,它不包括隐藏文件)
要计算文件或目录,您需要稍微改变策略。在这种情况下,我会使用ls -l它,因为它显示了什么是目录以及什么是 aa 文件。
$ 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
Run Code Online (Sandbox Code Playgroud)
然后我们可以使用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
Run Code Online (Sandbox Code Playgroud)
现在只需wc -l再次使用以计算上述内容:
# directories
$ ls -l | grep "^d" | wc -l
3
# regular files
$ ls -l | grep "^-" | wc -l
3
Run Code Online (Sandbox Code Playgroud)
不过,您可以wc完全避免,并使用grep's-c选项:
$ ls -l | grep -c '^d'
Run Code Online (Sandbox Code Playgroud)
(同样,隐藏文件不包括在内。请注意,目录和常规文件是两种类型的文件。还有更多,如命名管道、符号链接、设备、套接字......)。
如果您需要递归地查找文件和目录,/usr/bin那么您可能希望完全改变策略并使用另一个名为find.
$ find /usr/bin | wc -l
4632
Run Code Online (Sandbox Code Playgroud)
(虽然以上/usr/bin本身已包含在计数中)
我上面使用的相同技术可以用来ls做类似的事情,但ls通常不是解析输出的好工具。find另一方面是为此而构建的,并提供用于查找文件或目录的开关。
# find files
$ find /usr/bin -type f
# find directories
$ find /usr/bin -type d
Run Code Online (Sandbox Code Playgroud)
(请注意,这一次,find包括隐藏文件(除了.和..))。
我一直不明白为什么换行符是创建文件名或目录名时使用的合法字符。因此,上面讨论的方法使用wc和ls不会与这些方法相抗衡,因此请牢记使用它们。
使用换行符创建目录和文件名。
$ mkdir $'dir4\n5'
$ touch $'fileD\nE'
Run Code Online (Sandbox Code Playgroud)
ls 正确显示它们:
$ ls -1
dir1
dir2
dir3
dir4?5
fileA
fileB
fileC
fileD?E
Run Code Online (Sandbox Code Playgroud)
但是wc将包含换行符的目录和文件计为 2 个项目,而不是一个。
$ ls -1 | wc -l
10
Run Code Online (Sandbox Code Playgroud)
如果使用 的 GNU 实现,解决此问题的一种方法find是利用find的功能打印其他内容来代替它找到的每个文件,然后对其进行计数。
$ find . -printf . | wc -c
9
Run Code Online (Sandbox Code Playgroud)
在这里,我们找到当前目录中的所有内容(除了..),并.为每个打印一个点 ( ),然后使用wc的计算字节数而不是行数的能力计算点数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 (&)/'
Run Code Online (Sandbox Code Playgroud)
在/usr/bin我的系统上,这给出了:
3727 regular files
710 symbolic links
Run Code Online (Sandbox Code Playgroud)
在/dev:
83 block devices
203 character devices
31 directories
426 symbolic links
1 FIFOs
1 Unix domain sockets
Run Code Online (Sandbox Code Playgroud)
对于符号链接,如果您更愿意将它们视为它们指向的文件类型而不是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 (&)/'
Run Code Online (Sandbox Code Playgroud)
现在为我提供/usr/bin:
1 directories
4434 regular files
2 broken symbolic links
Run Code Online (Sandbox Code Playgroud)
(损坏的符号链接是find无法确定类型的文件的符号链接,因为该文件不存在,或者位于您无权访问的目录中,或者文件路径的解析中存在循环. 在我的情况下,那些 2 个文件的符号链接现在已经消失了)。
这些都不算数.和..。如果您希望将它们包括在内(为什么要这样做?),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 (&)/'
Run Code Online (Sandbox Code Playgroud)
然后给出我的/usr/bin:
2 directories
3727 regular files
710 symbolic links
Run Code Online (Sandbox Code Playgroud)
如果您无权访问 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
Run Code Online (Sandbox Code Playgroud)
现在,严格来说,我们不是在计算文件,而是在计算目录条目。一个目录 like/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
Run Code Online (Sandbox Code Playgroud)
这些是同一个文件(inode 为 672252 的那个)的 3 个目录条目(又名文件名,又名硬链接)。要计算文件而不是目录条目以及 GNUfind和 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 (&)/'
Run Code Online (Sandbox Code Playgroud)
在我的/usr/bin,这给出:
3711 regular files
710 symbolic links
Run Code Online (Sandbox Code Playgroud)