人类可读的文件大小和行数

Human-readable filesize and line count

我想要一个 bash 命令,它将 return 一个 table,其中每一行都是人类可读的文件大小、行数和文件名。 table 应按文件大小排序。

我一直在尝试结合使用 du -hswc -lsort -hfind

这是我所在的位置:

find . -exec echo $(du -h {}) $(wc -l {}) \; | sort -h

问题是您的 shell 解释了 $(...),所以 find 没有理解它们。转义它们也无济于事 ($\(du -h {}\)),因为它们成为命令的正常参数,而不是命令替换。

为了将它们解释为命令替换是调用一个新的shell,或者直接

find . -exec bash -c 'echo $(du -h {}) $(wc -l {})' \; | sort -h

或通过创建脚本并从 find 调用它。

好的,我也用 find/-exec 试过了,但是转义很麻烦。使用 shell 函数,它的工作非常简单:

#!/bin/bash
function dir
{
    du=$(du -sh "" | awk '{print }')
    wc=$(wc -l < "")
    printf "%10s %10s %s\n" $du $wc "${1#./}"
}

printf "%10s %10s %s\n" "size" "lines" "name"
OIFS=$IFS; IFS=""
find . -type f -print0 | while read -r -d $'[=10=]' f; do dir "$f"; done
IFS=$OIFS

使用 basishm read 通过使用 nul 终止符甚至是安全的。需要 IFS 来避免读取以截断文件名中的尾随空白。

顺便说一句:$'[=12=]' 并没有真正起作用(与 '' 相同)- 但它使意图明确。

示例输出:

      size      lines name
      156K        708 sash
       16K         64 hostname
      120K        460 netstat
       40K        110 fuser
      644K       1555 dir/bash
       28K         82 keyctl
      2.3M       8067 vim

您的方法不尽如人意,不仅因为 shell 扩展了您的命令替换 ($(...)) 预先,但更根本的原因是 您无法将 shell 命令行 直接 传递给 find:

find-exec 操作只能调用 外部实用程序 文字 arguments - 唯一支持的非文字参数是 {} 表示手头的文件名。

通过 在每次迭代中调用一个单独的 shell 实例 来解决您的直接问题,要执行的 shell 命令是作为 字符串参数传递 (-exec bash -c '...' \;).
虽然这是可行的(假设您将 {} 值作为 参数 传递,而不是将其嵌入命令行字符串中),但它也 相当 低效,因为为每个输入文件创建了多个子进程

(虽然 一种让 find 将(通常)所有输入文件传递给(通常) 单个 调用指定的外部实用程序 - 即使用终止符 + 而不是 \;,这是 而不是 由于传递的命令行的性质,这里是一个选项。 )

高效且稳健[1] 最小化子进程数量的实现创建看起来像这样:

注意:由于使用了 head -n -1sort -h.[=90=,我假设这里使用 GNU 实用程序] 此外,我将 find 的输出限制为仅 files(与目录相反),因为 wc -l 仅适用于 files.

paste <(find . -type f -exec du -h {} +) <(find . -type f -exec wc -l {} + | head -n -1) |
  awk -F'\t *' 'BEGIN{OFS="\t"} {sub(" .+$", "", ); print ,,}' |
   sort -h -t$'\t' -k1,1
  • 注意使用 -exec ... + 而不是 -exec ... \;,这确保通常 所有 输入文件名都传递给 对外部实用程序的单个 调用(如果不是所有文件名都适合单个命令行,调用将有效地分批处理以尽可能少地调用)。

  • wc -l {} + 总是输出摘要行,head -n -1 将其删除,但也会在每行计数后输出文件名。

  • paste 将每个命令的行(其各自的输入由进程替换提供。<(...))组合成单个输出流。

  • 然后 awk 命令从每行的末尾删除源自 wc 的无关文件名。

  • 最后,sort 命令按人类可读的数字(-h),例如 du -h 输出的数字(例如 1K)。


[1] 与任何面向 line 的处理一样,不支持嵌入 newlines 的文件名,但是我不认为这是一个现实世界的问题。