![如何计算目录中每个文件的行数,然后创建 n 行文件数的摘要](https://linux22.com/image/209940/%E5%A6%82%E4%BD%95%E8%AE%A1%E7%AE%97%E7%9B%AE%E5%BD%95%E4%B8%AD%E6%AF%8F%E4%B8%AA%E6%96%87%E4%BB%B6%E7%9A%84%E8%A1%8C%E6%95%B0%EF%BC%8C%E7%84%B6%E5%90%8E%E5%88%9B%E5%BB%BA%20n%20%E8%A1%8C%E6%96%87%E4%BB%B6%E6%95%B0%E7%9A%84%E6%91%98%E8%A6%81.png)
我正在尝试创建一个目录中有多少个文件有 n 行的摘要。我用来wc -l * | sort
打印每个文件名的行数。我想要实现的是目录的摘要,该目录将产生:
56 5
60 6
3 7
等等,其中第一列代表文件数,第二列代表行数。
我查看了一个 awk 命令awk 'END{print NR}' directory/*
,它返回整个目录中的行数。我考虑过printf
格式化wc -l
输出的解决方案。任何帮助将不胜感激!谢谢
答案1
使用 GNU awk
,你可以这样做:
find . -type f -print0 | gawk '
BEGIN {
RS = "\0"
while ((getline < "-") > 0) ARGV[ARGC++] = $0
if (ARGC == 1) exit
RS = "\n"
}
ENDFILE {count[FNR]++}
END {
PROCINFO["sorted_in"] = "@ind_num_asc"
for (i in count) print count[i], i
}'
find -print0
我们通过从的输出中读取以 NUL 分隔的文件来设置要在 BEGIN 语句中处理的文件列表。
或者与以下相同perl
(注意空文件将被忽略):
find . -type f -print0 | perl -0 -ne '
BEGIN{@ARGV = <STDIN>; $/ = "\n"}
if (eof) {$count{$.}++; close ARGV}
END {print "$count{$_} $_\n" for sort {$a <=> $b} keys %count}'
请注意,它们计算行数(无论是否分隔),同时wc -l
计算换行符的数量。例如,对于使用printf foo > file
where创建的文件wc -l
会报告 0 但perl
/ gawk
1,这会有所不同。
使用wc
POSIXly,你可以这样做:
find .//. -type f -exec wc -l {} + | LC_ALL=C awk '
/\/\// {count[$1]++}
END {for (i in count) print count[i], i}' | sort -k2n
通过使用.//.
,我们可以知道文件路径在输出中从哪一行开始wc
(因为//
不能出现在其他地方),并且行计数将是该行的第一个字段,因此我们可以可靠地处理包含换行符的文件路径。这还跳过了传递多个参数的调用在末尾打印的total
行,因为它不包含.wc
//
使用 GNUgrep
或兼容版本,您还可以执行以下操作:
LC_ALL=C grep -rch '^' . | sort -n | uniq -c
我们正在c
计算匹配的行数^
,即有一个开头,因此所有文件中的所有行都r
在 中递归.
,-h
以跳过打印文件名。LC_ALL=C
不必费心将内容解码为文本(grep
鉴于该正则表达式,GNU 至少可能会优化该解码)。
请注意,所有这些也计入隐藏文件。
要跳过它们,您可以将命令更改find
为:
LC_ALL=C find . -name '.?*' -prune -o -type f -print0
grep -r
尽管您可以删除-r
并将find
文件列表传递给 ,但GNU 没有等效项grep
:
LC_ALL=C find . -name '.?*' -prune -o -type f -exec grep -ch {} +
答案2
假设您的“wc -l *”按照您需要的方式计算行数,例如没有有趣的文件名,那么您可以使用 uniq -c 为您进行计数。 head -n -1 是去掉末尾的“total”行:
wc -l *|head -n -1|sort|awk '{print $1}'|uniq -c