bash - 如何有效地列出正好有 `n` 行的文件?

标签 bash performance file awk find

为了列出正好有 n 行的文件,可以这样做

n=5
find . -name "*.txt" | xargs wc -l | awk -v n=${n} -F" " '{if ($1==n) {print $2} }'

但是这个解决方案非常慢,因为它首先计算每个文件的行数,然后只选择那些有 n 行的文件。计算行数并在到达 n+1 行时停止的进程会更有效率(尤其是在处理包含大量行的大文件时)。

如何有效地列出正好有 n 行的文件?

请注意,对于特殊情况,每行的大小完全相同,那么可能可以这样做

n=5
sizePerLine=500
find . -name '*.txt' -size $(( ${n} * ${sizePerLine} ))

最佳答案

我认为以下会更快:

find . -name "*.txt" -exec awk -v n="$n" 'FILENAME != prevfile {if(prevfnr==n) print prevfile} {prevfile = FILENAME; prevfnr = FNR; if(FNR>n) {nextfile;}} END{if (FNR==n) {print FILENAME} }' {} +

工作原理:

  • 使用 -exec ... {} + 使用 find 为每个文件执行命令,并让它在每次调用时传递许多参数
  • awk -v n="$n" 调用 awk 并定义一个名为 nawk 变量与 shell 变量 n
  • 相同的值
  • FILENAME != prevfile {if(prevfnr==n) print prevfile 检查当前文件是否与上一条记录相同,如果不相同,则查看前一个文件是否完全 n 条记录,如果有则打印该文件的名称
  • {prevfile = FILENAME; prevfnr = FNR; if(FNR>n) {nextfile;}} 用当前的 FILENAME 更新 prevfile 变量,用当前的 prevfnr 变量更新当前 FNR。另外,如果我们当前的文件记录超过n,则跳转到下一个文件,这里不做任何处理
  • END{if (FNR==n) {print FILENAME} 最后看看最后一个文件是否也正好有 n 条记录

有趣的是,我发现这实际上给出了与使用 wc -l 的版本不同的结果,尽管我认为这个可能更正确。对于我目录中最后一行不包含行结束字符的文件 wc -l 将报告行数,不计算最后一个“未终止”行,但这里的解决方案将计算它。

Arg,我没有意识到 nextfile 是 GNU 主义。如果我已经将自己限制在这一点上,我们可以使它更干净,因为

find . -name '*.txt' -exec  awk -v n="$n" 'FNR > n {nextfile;} ENDFILE{if (FNR==n) {print FILENAME} }' {} +

在我看来,POSIX awk 没有很好的快捷方式来跳转到下一个文件,这是该解决方案提高效率所需的关键

关于bash - 如何有效地列出正好有 `n` 行的文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39431845/

相关文章:

bash - Bash 中具有浮点值的 C 风格算术

multithreading - Intel Nehalem 单线程峰值性能

java - 从 Uri 获取路径

将文本文件中的小写字符转换为大写字母,反之亦然

bash - 递归查找不在排除文件中的所有文件

c++ - 如何从集合中删除共享 ptr 元素?

Linux 命令输出未被重定向

linux - 如何限制系统上的页面缓存量?

java - 应用于没有 try-catch bug 的函数的 JVM 优化是否会引发异常?

eclipse - 让 IntelliJ IDEA 刷新项目并检测更改的文件