在所有目录中执行文件类型计数

3
我有一个bash脚本,可以递归地给出所有目录中在过去45天内编辑过的文件数量。
 find . -type f -mtime -45| rev | cut -d . -f1 | rev | sort | uniq -ic | sort -rn

我有一个名为的目录。
\parent

"而在父级中,我有:"
\parent\a
\parent\b
\parent\c

我会在文件夹 abc 上分别运行上述脚本一次。
当前的输出结果是:
     91 xls
     85 xlsx
     49 doc
     46 db
     31 docx
     24 jpg
     22 pub
     10 pdf
      4 msg
      2 xml
      2 txt
      1 zip
      1 thmx
      1 htm
      1 /ic

我想要在\parent内的所有文件夹上运行脚本,并获得如下输出:
+-------+------+--------+
| count | ext  | folder |
+-------+------+--------+
|    91 | xls  | a      |
|    85 | xlsx | a      |
|    49 | doc  | a      |
|    46 | db   | a      |
|    31 | docx | a      |
|    24 | jpg  | a      |
|    22 | pub  | a      |
|    10 | pdf  | a      |
|     4 | msg  | a      |
|    98 | jpg  | b      |
|    92 | pub  | b      |
|    62 | pdf  | b      |
|     2 | xml  | b      |
|     2 | txt  | b      |
|     1 | zip  | b      |
|     1 | thmx | b      |
|     1 | htm  | b      |
|     1 | /ic  | b      |
|    66 | txt  | c      |
|    48 | msg  | c      |
|    44 | xml  | c      |
|    30 | zip  | c      |
|    12 | doc  | c      |
|     6 | db   | c      |
|     6 | docx | c      |
|     3 | jpg  | c      |
+-------+------+--------+

如何使用bash完成这个任务?

rev 是什么,为什么要使用它? - emil
我从这里得到了它:http://bran.name/dump/bash-build-aggregated-sorted-list-of-file-extensions-in-a-directory-and-count/ 我认为它只是对其进行排序,我不确定。 - Alex Gordon
看起来,构造rev | cut -d . -f1 | rev是一种奇怪(但也有点巧妙)的方式,可以完成sed 's/\(.*\)\.\(.+\?\)/\2/g'的功能,后者只是从每个文件名中提取文件扩展名。 - nullrevolution
1个回答

5
将它放入一个脚本中,使其可执行:chmod +x script.sh,然后使用以下命令运行:./script.sh
#!/bin/sh

find . -type f -mtime -45 2>/dev/null \
    | sed 's|^\./\([^/]*\)/|\1/|; s|/.*/|/|; s|/.*.\.| |p; d' \
    | sort | uniq -ic \
    | sort -b -k2,2 -k1,1rn \
    | awk '
BEGIN{ 
    sep = "+-------+------+--------+"
    print sep "\n| count | ext  | folder |\n" sep
}

{ printf("| %5d | %-4s | %-6s |\n", $1, $3, $2) }

END{ print sep }'
  • sed 's|^\./\([^/]*\)/|\1/|; s|/.*/|/|; s|/.*.\.| |p; d'

    1. s|^\./\([^/]*\)/.*/|\1 |./a/file.xls 替换为 a/file.xls
    2. s|/.*/|/|b/some/dir/file.mp3 替换为 b/file.mp3
    3. s|/.*.\.| |p 如果 s///p 成功,将 a file.xls 替换为 a xls 并输出到标准输出(避免没有扩展名的文件)。
    4. d 删除该行(避免重复打印匹配或不匹配的行)。
  • sort | uniq -ic 计算每个扩展名和目录名称组合的数量。

  • sort -b -k2,2 -k1,1rn 先按目录(第2列)排序,从小到大,然后按数量(第1列)倒序排序(从大到小),并以数字方式排序。 -b 使 sort(1) 忽略空格/制表符。

  • 最后的 awk 部分美化输出,也许你想将其放入单独的脚本中。

如果想查看每个管道过滤结果的方式,只需尝试删除每个管道即可看到输出。

在这里您可以找到有关 sh/awk/sed 等的好教程。

http://www.grymoire.com/Unix/


非常感谢您!我将您的脚本复制并粘贴到Shell中,但它仅为1个目录提供了结果。 - Alex Gordon
嗨,问题是"$@"保存了传递给脚本的参数。如果你只是将其复制粘贴到终端中,它将始终为空。现在我修改了一下,所以如果你想要复制粘贴脚本,它也能处理当前目录中的文件。 - emil
你好!非常感谢,这个工作得非常好!!!请问为什么它只返回每个目录的前 10 个结果?我该如何让它返回每个目录的所有结果? - Alex Gordon
也许它们在过去的45天内没有被修改过,尝试移除“-mtime -45”。 - emil
非常棒的答案!非常感谢。你能告诉我 sed 命令是做什么的吗?你是如何想到它的呢?它看起来太高级了。 - Alex Gordon
哈哈,谢谢你,你太好了。 :) 我尽可能地解释了 sed 命令的每个部分。我认为最简单的方法就是阅读上面链接中的 sed 章节,并尝试删除 sed 命令的部分。 - emil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接