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

时间:2016-08-13 23:15:59

标签: bash wc du

我想要一个返回表的bash命令,其中每一行都是人类可读的文件大小,行数和文件名。该表应按文件大小排序。

我一直尝试使用du -hswc -lsort -h以及find的组合来完成此操作。

这是我在的地方:

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

3 个答案:

答案 0 :(得分:1)

好的,我也尝试使用find / -exec,但逃避是地狱。使用shell函数,它非常直接:

.catch(){}

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

BTW:#!/bin/bash function dir { du=$(du -sh "$1" | awk '{print $1}') wc=$(wc -l < "$1") 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 $'\0' f; do dir "$f"; done IFS=$OIFS 并不真正起作用(与$'\0'相同) - 但它使意图明确。

示例输出:

''

答案 1 :(得分:1)

您的方法不尽如人意,不仅因为 shell扩展了您的命令替换($(...)预先 ,更基本的原因是因为您无法通过 shell 命令行直接find

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

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

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

高效且强大的 [1]  最小化子进程数的实现将如下所示:

注意:由于使用了\;head -n -1,我在这里假设 GNU 实用程序。
另外,我只将sort -h的输出限制为文件(而不是目录),因为find仅适用于文件。< / SUP>

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

  • -exec ... \;总是会输出一个摘要行,wc -l {} +会消失,但也会在每行计数后输出文件名。

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

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

  • 最后,wc命令按第一个(sort)制表符分隔的(-k1,1)列按人类可读的数字(-t$'\t'对结果进行排序),例如-h输出的数字(例如du -h)。

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

答案 2 :(得分:0)

问题是你的shell会解释$(...),因此find无法获取它们。逃避它们也没有帮助(\$\(du -h {}\)),因为它们成为命令的正常参数,而不是命令替换。

为了将它们解释为命令替换是直接调用新的shell

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

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