列出目录中的小文件并输出汇总

List small files in a directory and output a summary total

我想 (1) 识别目录中小于 64 字节的文件并 (2) 打印出它们的名称和大小。以下一行代码完成了这项工作:

find . -size -64c -exec ls -lh {} \;|awk '{print , }'

这将打印出文件列表及其大小。 我可以轻松地扩展这个单行代码以打印出找到的文件总数吗?实际上是将文件列表通过管道传输到 wc -l 命令中吗?

Can I easily extend this one-liner to also print out the total number of files found.

是的,通过在 END 块打印 NR

... | awk '{ print ,  } END { print NR }'

您还可以添加后缀:

... END { print "Total number of files found: " NR }'

考虑改为这样做:

find . -size -64c -printf '%s %p\n' | awk '1; END{print NR}'

这意味着您不会生成一个子 shell 来对找到的每个文件调用 ls,因此它会更有效率并且可以轻松调整以处理包含任何字符的文件名,包括换行符,例如使用 GNU 工具允许 NUL 分隔文件名:

find . -size -64c -printf '%s %p[=11=]' | awk -v RS='[=11=]' '1; END{print NR}'

如果您希望 awk 输出也以 NUL 分隔,请添加 -v ORS='[=16=]'

如果你不想那样做,至少改变一下:

find . -size -64c -exec ls -lh {} \;

至:

find . -size -64c -exec ls -lh {} +

所以 ls 是针对一组文件而不是一次调用一个。

请注意,@dawg 在评论中提到 -printf 可能仅适用于 GNU。

您也可以使用简短的 Python 脚本和 pathlib 来替换 findawk:

python3 -c 'from pathlib import Path
cnt, fsum=0,0
for fn in (x for x in Path().glob("**/*") if x.is_file() and x.stat().st_size<64):
    size=fn.stat().st_size
    print(f"{str(fn)}: {size:,} bytes")
    fsum+=size
    cnt+=1
    
print(f"Total files: {cnt:,} Total bytes: {fsum:,}")'

一些关键要素:

  1. Path() 的空参数引用本地目录 . 您也可以使用 Path(".") 来使用当前目录。您还可以在那里指定一个特定路径作为文件树的根。
  2. glob glob("**/*") 是对 Path 指定文件中或以下文件的所有文件的递归目录遍历 -- 类似于 find

或在ruby:

ruby -e '
fsum=0; cnt=0
Dir.glob("**/*").each{|fn| 
    st=File.stat(fn)
    if (st.size<64 && st.file?)
        puts "#{fn}: #{st.size} bytes" 
        cnt+=1
        fsum+=st.size
    end
}
puts "Total files: #{cnt} Total bytes: #{fsum}"'