我想要一个返回表的bash命令,其中每一行都是人类可读的文件大小,行数和文件名。该表应按文件大小排序。
我一直尝试使用du -hs
,wc -l
和sort -h
以及find
的组合来完成此操作。
这是我在的地方:
find . -exec echo $(du -h {}) $(wc -l {}) \; | sort -h
答案 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
调用它。