输出将包括目录名、文件名和文件大小。运行命令的每个目录都有一个(最大文件)。
如果可能的话,也请提供该目录中文件的平均大小。
目的是可以在目录中查找比目录中其他文件大得多的文件,以便可以替换它们
答案1
使用 GNU find
、sort
和sed
(4.2.2 或更高版本),根据文件大小排序一次,然后根据目录路径再次排序:
find /some/dir -type f -printf '%s %f%h\0' |
sort -zrn |
sort -zut/ -k2 |
sed -zre 's: ([^/]*)(/.*): \2/\1:'
解释:
- 打印文件大小、名称和路径(第一个由空格分隔,后两个由 分隔
/
),每个条目均以 ASCII NUL 字符终止。 - 然后,我们使用大小进行数字排序,假设 NUL 分隔输出(并且按相反顺序,因此最大的文件在前)。
- 然后,我们使用第二个分隔字段中的所有内容(该字段是包含该文件的目录的路径)
sort
仅打印第一个唯一条目。/
- 然后我们使用
sed
交换目录和文件名,这样我们就得到了一个正常的路径。
为了获得可读的输出,请将 ASCII NUL 替换为换行符:
find /some/dir -type f -printf '%s %f%h\0' |
sort -zrn |
sort -zut/ -k2 |
sed -zre 's: ([^/]*)(/.*): \2/\1:' |
tr '\0' '\n'
输出示例:
$ find /var/log -type f -printf '%s %f%h\0' | sort -zrn | sort -zt/ -uk2 | sed -zre 's: ([^/]*)(/.*): \2/\1:' | tr '\0' '\n'
3090885 /var/log/syslog.1
39789 /var/log/apt/term.log
3968 /var/log/cups/access_log.1
31 /var/log/fsck/checkroot
467020 /var/log/installer/initial-status.gz
44636 /var/log/lightdm/seat0-greeter.log
15149 /var/log/lxd/lxd.log
4932 /var/log/snort/snort.log
3232 /var/log/unattended-upgrades/unattended-upgrades-dpkg.log
答案2
结合find
并awk
也可以计算平均值:
find . -type f -printf '%s %h/%f\0'|awk 'BEGIN { RS="\0" } { SIZE=$1; for (i = 1; i <= NF - 1; i++) $i = $(i + 1); NF = NF - 1; DIR=$0; gsub("/[^/]+$", "", DIR); FILE=substr($0, length(DIR) + 2); SUMSIZES[DIR] += SIZE; NBFILES[DIR]++; if (SIZE > MAXSIZE[DIR] || !BIGGESTFILE[DIR]) { MAXSIZE[DIR] = SIZE; BIGGESTFILE[DIR] = FILE } }; END { for (DIR in SUMSIZES) { printf "%s: average %f, biggest file %s %d\n", DIR, SUMSIZES[DIR] / NBFILES[DIR], BIGGESTFILE[DIR], MAXSIZE[DIR] } }'
AWK 脚本以更易读的方式排列:
BEGIN { RS="\0" }
{
SIZE=$1
for (i = 1; i <= NF - 1; i++) $i = $(i + 1)
NF = NF - 1
DIR=$0
gsub("/[^/]+$", "", DIR)
FILE=substr($0, length(DIR) + 2)
SUMSIZES[DIR] += SIZE
NBFILES[DIR]++
if (SIZE > MAXSIZE[DIR] || !BIGGESTFILE[DIR]) {
MAXSIZE[DIR] = SIZE
BIGGESTFILE[DIR] = FILE
}
}
END {
for (DIR in SUMSIZES) {
printf "%s: average %f, biggest file %s %d\n", DIR, SUMSIZES[DIR] / NBFILES[DIR], BIGGESTFILE[DIR], MAXSIZE[DIR]
}
}
这需要空分隔的输入记录(我从穆鲁的回答);对于每个输入记录,它
- 存储大小(供以后使用),
- 删除路径中第一个字符之前的所有内容(因此我们至少正确处理带空格的文件名),
- 提取目录,
- 提取文件名,
- 将我们之前存储的大小添加到目录中的大小总和中,
- 增加目录中的文件数量(这样我们就可以计算平均值),
- 如果大小大于存储的目录最大大小,或者如果我们尚未在目录中看到文件,则更新最大文件的信息。
完成所有操作后,脚本将循环输入键SUMSIZES
并输出目录、平均大小、最大文件名和大小。
您可以通过管道将输出sort
按目录名称排序。如果您想以人性化的形式另外设置尺寸格式,您可以将该printf
行更改为
printf "%.2f %d %s: %s\n", SUMSIZES[DIR] / NBFILES[DIR], MAXSIZE[DIR], DIR, BIGGESTFILE[DIR]
然后将输出通过管道传输到numfmt --field=1,2 --to=iec
.您仍然可以按目录名称对结果进行排序,只需从第三个字段开始排序:sort -k3
。
答案3
兹什的通配符模式对于你正在做的事情非常有用。具体来说,zsh可以通过类型、大小等属性来匹配文件全局限定符。 Glob 限定符还允许对匹配项进行排序。
例如,在 zsh 中,*(.DOLN[1])
扩展为当前目录中最大文件的名称。*
是文件名的模式(匹配所有内容,除了可能的点文件,具体取决于 shell 选项)。限定符.
将匹配限制为常规文件,D
导致*
包含点文件,OL
按递减大小(“长度”)排序,N
如果根本没有匹配文件,则导致扩展为空,并[1]
仅选择第一个匹配。
您可以使用 递归枚举目录**/
。例如,以下循环递归地迭代当前目录及其子目录的所有子目录:
for d in **/*(/); do … done
您可以使用zstat
访问文件的大小和其他元数据,而无需依赖其他工具进行解析。
zmodload -F zsh/stat b:zstat
files=(*(DNoL))
zstat -A sizes +size -- $files
total=0; for s in $sizes; do total+=$s; done
if ((#sizes > 0)); then
max=$sizes[-1]
average=$((total/#sizes))
median=$sizes[$((#sizes/2))]
fi
答案4
考虑使用 baobab 或一些类似的软件,其中一个或多个可能包含在您的发行版中。他们很好地可视化了问题目录。
- 猴面包树
- JDisk报告
- NCDU
- K4DirStat
- QDirStat
- 广东省地图
http://alternativeto.net/software/baobab/?platform=linux
猴面包树的手册页告诉了它它是怎么回事。
$> man baobab
BAOBAB(1)
NAME
Baobab - A graphical tool to analyse disk usage
SYNOPSIS
baobab [directory]
DESCRIPTION
baobab is able to scan either specific folders or the whole filesys-
tem (local and remote), in order to give the user a graphical tree
representation including each directory size or percentage in the
branch. It also auto-detects in real-time any change made to your
home directory as far as any mounted/unmounted device. A graphical
treemap window is also provided for any selected folder.
A detailed documentation on the program could be read at:
http://www.gnome.org/projects/baobab
AUTHOR
Fabio MARZOCCA <[email protected]>
BAOBAB(1)