列出目录中的小文件并输出汇总
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 来替换 find
和 awk
:
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:,}")'
一些关键要素:
Path()
的空参数引用本地目录 .
您也可以使用 Path(".")
来使用当前目录。您还可以在那里指定一个特定路径作为文件树的根。
- 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}"'
我想 (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 来替换 find
和 awk
:
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:,}")'
一些关键要素:
Path()
的空参数引用本地目录.
您也可以使用Path(".")
来使用当前目录。您还可以在那里指定一个特定路径作为文件树的根。- 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}"'