67291a9a50
Introduce ff script -h with auto descriptions, shared help.sh, and usage flags across script/*.sh. Co-authored-by: Cursor <cursoragent@cursor.com>
132 lines
2.8 KiB
Bash
Executable File
132 lines
2.8 KiB
Bash
Executable File
#!/bin/bash
|
|
# 查询目录大小(du 封装,支持排序与 Top N)
|
|
|
|
set -eu
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
用法: dirsize [选项] [目录]
|
|
|
|
查询目录大小,默认列出当前目录下的直接子目录和子文件。
|
|
|
|
选项:
|
|
-a, --all 递归显示所有子目录的大小
|
|
-d, --depth N 指定递归深度 (默认 1)
|
|
-n, --top N 只显示前 N 名 (默认全部)
|
|
-r, --reverse 按从小到大排序 (默认从大到小)
|
|
-h, --help 显示帮助信息
|
|
|
|
示例:
|
|
dirsize 当前目录的直接子项大小
|
|
dirsize -n 10 当前目录的直接子项,取前 10 名
|
|
dirsize -a 递归显示所有子目录
|
|
dirsize -d 2 -n 5 深度 2,取前 5 名
|
|
dirsize -n 5 /var/log 查看 /var/log 的子项,取前 5 名
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
DEPTH=1
|
|
TOP=0
|
|
REVERSE=false
|
|
ALL=false
|
|
TARGET_DIR="."
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-a | --all)
|
|
ALL=true
|
|
shift
|
|
;;
|
|
-d | --depth)
|
|
DEPTH="$2"
|
|
shift 2
|
|
;;
|
|
-n | --top)
|
|
TOP="$2"
|
|
shift 2
|
|
;;
|
|
-r | --reverse)
|
|
REVERSE=true
|
|
shift
|
|
;;
|
|
-h | --help) usage ;;
|
|
-*)
|
|
echo "未知选项: $1" >&2
|
|
usage
|
|
;;
|
|
*)
|
|
TARGET_DIR="$1"
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ ! -d "$TARGET_DIR" ]]; then
|
|
echo "错误: '$TARGET_DIR' 不是有效目录" >&2
|
|
exit 1
|
|
fi
|
|
|
|
TARGET_DIR="$(cd "$TARGET_DIR" && pwd -P)"
|
|
|
|
if $ALL; then
|
|
DEPTH=999
|
|
fi
|
|
|
|
sort_flag="-rh"
|
|
if $REVERSE; then
|
|
sort_flag="-h"
|
|
fi
|
|
|
|
list_dir_sizes() {
|
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
sudo du -h -d "$DEPTH" "$TARGET_DIR" 2>/dev/null
|
|
else
|
|
sudo du -h --max-depth="$DEPTH" "$TARGET_DIR" 2>/dev/null
|
|
fi | awk -v dir="$TARGET_DIR" '$2 != dir {print}'
|
|
}
|
|
|
|
# 用 ls 读取直接子文件(一次 readdir),避免 find 递归
|
|
list_direct_file_sizes() {
|
|
sudo ls -lA "$TARGET_DIR" 2>/dev/null | awk -v dir="$TARGET_DIR" '
|
|
function human(bytes, units, i, size) {
|
|
split("B K M G T", units, " ")
|
|
i = 1
|
|
size = bytes
|
|
while (size >= 1024 && i < 5) {
|
|
size /= 1024
|
|
i++
|
|
}
|
|
if (i == 1) {
|
|
return sprintf("%dB", bytes)
|
|
}
|
|
return sprintf("%.1f%s", size, units[i])
|
|
}
|
|
/^-/ {
|
|
name = $9
|
|
for (i = 10; i <= NF; i++) {
|
|
name = name " " $i
|
|
}
|
|
printf "%s\t%s/%s\n", human($5), dir, name
|
|
}
|
|
'
|
|
}
|
|
|
|
result=$(
|
|
{
|
|
list_dir_sizes
|
|
list_direct_file_sizes
|
|
} | sort $sort_flag
|
|
)
|
|
|
|
if [[ "$TOP" -gt 0 ]]; then
|
|
result=$(echo "$result" | head -n "$TOP")
|
|
fi
|
|
|
|
if [[ -z "$result" ]]; then
|
|
echo "目录为空"
|
|
exit 0
|
|
fi
|
|
|
|
echo "$result"
|