我想要一个将返回一个表的bash命令,其中每行是可读的文件大小,行数和文件名。该表应按文件大小排序。人类可读的文件大小和行数
我一直在努力做到这一点使用的du -hs
,wc -l
和sort -h
和find
的组合。
下面是我在哪里:
find . -exec echo $(du -h {}) $(wc -l {}) \; | sort -h
我想要一个将返回一个表的bash命令,其中每行是可读的文件大小,行数和文件名。该表应按文件大小排序。人类可读的文件大小和行数
我一直在努力做到这一点使用的du -hs
,wc -l
和sort -h
和find
的组合。
下面是我在哪里:
find . -exec echo $(du -h {}) $(wc -l {}) \; | sort -h
你的做法短期下跌不仅是因为外壳扩展您的命令替换($(...)
)前面,但更根本的,因为你不能传递外壳命令行直接至find
:
find
的-exec
动作只能调用外部公用事业与字面参数 - 支持的唯一非文字形参是表示手头的文件名(多个){}
。
choroba's answer修复您通过眼前的问题在每次迭代中调用一个单独的壳例如,为了外壳命令来执行作为字符串参数(-exec bash -c '...' \;
)被传递哪个。
虽然这工作(假设你通过{}
值作为参数而不是在命令行字符串嵌入它),它也是相当低效,因为多个子进程创建每个输入文件。
(虽然是办法有find
通(典型地)所有输入文件到一个(典型地)单调用指定的外部工具的 - 即与终止子+
而非\;
,这是不这里由于传递的命令行的性质的选项。)
一种高效且健壮的[1] 执行该孩子的数目最小化处理创建应该是这样的:
注:我假设这里GNU公用事业,由于使用的head -n -1
和sort -h
。
另外,我限制find
的输出文件只(而不是目录),因为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
输出(例如,1K
)。
[1]与任何线取向处理,嵌入式换行符文件名不支持,但我不认为这是一个现实世界的问题。
的问题是,你的shell解释$(...)
,所以find
没有得到他们。转义它们对(\$\(du -h {}\)
)无效,因为它们成为命令的正常参数,而不是命令替换。
为了它们解释为命令替换是调用一个新的外壳,无论是直接
find . -exec bash -c 'echo $(du -h {}) $(wc -l {})' \; | sort -h
,或者通过创建脚本,并从find
调用它。
是否有可能只显示文件名一次? – Hatshepsut
@Hatshepsut:当然,使用'wc -l <{}'。 – choroba
不幸的是,这将打破文件名与嵌入式元字符,如空格(并可能与嵌入式globbing字符)。 要解决这个问题,你必须使用'find。 -exec bash -c'echo'$(du -h“$ 1”)$(wc -l <“$ 1”)“' - {} \; |然而,即使这解决了OP的直接问题并且非常短,但这种方法对于大型输入文件集将执行得不好,因为它会创建多个子进程_per filename_。 – mklement0
好吧,我也试过用find/-exec,但逃跑是地狱。具有外壳功能,它的工作原理非常简单:
#!/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
使用basishm阅读它甚至可以使用nul终止符来保证安全。 IFS需要避免读取来截断文件名中的尾随空白。
顺便说一下:$'\0'
实际上并不奏效(与''
相同) - 但它使意图清晰。
输出示例:
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
告诉我们你得到了什么 – eckes
@eckes用非工作代码编辑 – Hatshepsut