我正在寻找类似的东西
du -h /var/log/ --max-depth=2 --threshold=5G
但为了du
如果空间高于该阈值,则在当前目录上再次执行。有没有办法在不重复原始输出的情况下保持顺序?
例如,对于 5Gb 的阈值:
10.3G /lib/
8.9G /lib/lib1
2.1G /lib/lib1/files1
6.3G /lib/lib1/files2
3.2G /lib/lib1/files2/foz
1.3G /lib/lib2
8.3G /tmp/
8.2G /tmp/foo
5.2G /tmp/foo/bar
5.1G /tmp/foo/bar/bar1
900M /tmp/foo/bar/bar2
1.0G /tmp/foo/bat
1.0G /tmp/foo/baz
最初尝试该命令时,我没有得到所需的输出。 for 循环或将 du 命令放入函数中会有帮助吗?提前致谢
答案1
它不是du
可以直接交付的东西,但一点点递归 shell 脚本可以充分包装它,以给出您想要的近似值。
首先,将所有这些放入一个文件中,例如/usr/local/bin/rdu
并使其可执行:
#!/bin/bash
shopt -s dotglob
# Pretty printer
du_pp() {
local value=$1 unitIndex=0 units="KMGTP"
while [ $value -ge 1024 ]
do
((unitIndex++)); value=$((value/1024))
done
echo "$value${units:$unitIndex:1}"
}
# Convert to K
du_ck() {
local value=$1 l=${#1} unit
((l--))
unit=${value:$l:1}
[[ 'KMGTP' == *"$unit"* ]] && value=${value:0:$l} || unit='K'
until [ "$unit" = 'K' ]
do
case "$unit" in
M) value=$((value*1024)) unit='K';;
G) value=$((value*1024)) unit='M';;
T) value=$((value*1024)) unit='G';;
P) value=$((value*1024)) unit='T';;
esac
done
echo $value
}
# Call du, recursively expanding nodes greater than the threshold
du_rx() {
local threshold=$1
shift
local starts=("$@")
du -ks "${starts[@]}" |
while IFS=$'\t' read -r size dir
do
printf '%s\t%s\n' "$(du_pp "$size")" "$dir"
if [ -d "$dir" ] && [ $size -ge $threshold ]
then
[ "$dir" == '/' ] && dir=
du_rx "$threshold" "$dir"/*
fi
done
}
# Call du_rx 1024000 /var
threshold=$(du_ck $1)
shift
starts=("$@")
du_rx $threshold "${starts[@]}"
至少使用两个参数调用它:以K
(默认)、M
、G
或T
表示的阈值大小P
,以及一个或多个起始目录。例如,
rdu 1000 /var/log # threshold is 1000 KiB
rdu 1G /var /usr # threshold is 1 GiB
这是它的工作原理。
有两个支持功能du_pp
和du_ck
。第一个将 KiB 中的值转换为“人类可读”的等价值,可以使用 MiB、GiB、TiB 或 PiB 单位。第二个将字符串转换为4G
等效的 KiB 值。两者都不稳定,但在大多数情况下都应该有效。
驱动函数是递归的du_rx
。这会遍历起始目录中的条目并调用du -s
它们来获取摘要大小。如果摘要大小超过阈值,则(自行)调用该函数,并将当前项目作为新的起始目录。
至于du
所有条目都是输出,而不仅仅是目录。您可以通过包装此块来避免这种情况:
printf '%s\t%s\n' "$(du_pp "$size")" "$dir"
if [ -d "$dir" ] && [ $size -gt $(du_ck "$threshold") ]
then
[ "$dir" == '/' ] && dir=
du_rx "$threshold" "$dir"/*
fi
像这样
if [ -d "$dir" ]
then
printf '%s\t%s\n' "$(du_pp "$size")" "$dir"
if [ $size -gt $(du_ck "$threshold") ]
then
[ "$dir" == '/' ] && dir=
du_rx "$threshold" "$dir"/*
fi
fi