如何使用wc和管道查找某个目录中有多少个文件和目录?


10

如何使用字计数器(wc)和管道计数目录中有多少个文件或/usr/bin目录?


这个作业?可以寻求帮助,只要有帮助就可以。
slm

是的,但是因为我是Linux的新手,所以我在这里发布有关如何实现某些目标的想法,并且它可能非常复杂。我已经用此命令解决了上面的问题
兑现

ls / bin / usr / bin | 排序 uniq | WC -
现金

np。寻求帮助是完全可以的!只是贴上标签,使人们知道,这里的每个人通常都很乐意帮助试图学习Unix的人们。
slm

Answers:


13

一种方法是利用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包括隐藏文件(.和除外..))。

换行符?

我从来没有想过为什么换行符是创建文件名或目录名时要使用的合法字符。因此,上面讨论的方法将使用wcls不会与之抗衡,因此请牢记这一点。

用换行符创建目录和文件名。

$ 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),但值得注意的是,所有这些文件都会在包含换行符的文件名上中断。
evilsoup 2013年

@evilsoup-不,我不相信ls -lls -1会打破b / c,我们正在计算行数,而不是文字!该find可破,但同样,我们就指望行不言。
slm

我的意思是,如果文件包含换行符,这将(我认为,我现在在Windows上,因此无法测试)中断。因此,touch $'foo\nbar'在一个空目录中,后跟您的命令之一(例如ls -1 | wc -l)将报告两个文件而不是一个文件-因为该文件相对于两行wc而言。除非ls用其他字符替换换行符(我不认为这样做,但是现在我无法进行测试)。
evilsoup

@evilsoup-正确,换行符。是合法字符。文件名,该方法将无法正确处理这些类型的文件名。
slm

@StephaneChazelas- wc -c在计算期间时是否有问题?
slm

5

如果要在某个目录下使用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

0

您没有说是要递归地将文件放在/ usr / bin下还是在第一级之下。另外,您将如何获得要数的单词?通常的查找方法是将find放入wc。像这样:查找/ usr / bin | wc -l Find将列出那里的所有内容,目录和文件。Wc -l将计算查找输出中的所有行。这是课堂作业吗?可以,但我想知道为什么您需要此信息,以便我可以更仔细地调整响应。如果您需要更多,请告诉我。哥斯达黎加


0

使用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

请注意,第二个在递归时将遵循符号链接(并将指向常规文件的符号链接视为常规文件,将指向dirs的符号链接视为dirs),将不对当前目录中的文件和目录进行计数,.并且也不对..条目进行计数。您可能要消除文件与常规文件的歧义。
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.