Files
linux_tools/file_size.sh
2026-06-01 02:03:00 +03:00

298 lines
9.1 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# Цвета как в zsh
COLOR_RESET='\033[0m'
COLOR_WHITE='\033[37m' # обычные файлы
COLOR_GREEN='\033[32m' # исполняемые (+x)
COLOR_CYAN='\033[36m' # аудио/видео
COLOR_RED='\033[31m' # архивы, бинарники
COLOR_YELLOW='\033[33m' # директории
# Типы аудио/видео
AUDIO_VIDEO_EXTS="mp4|mkv|avi|mov|flv|wmv|webm|m4v|3gp|ogv|ts|m2ts|mts|mp3|wav|flac|aac|ogg|wma|opus|m4a|alac|aiff"
# Дефолтные значения
DIRECTORY="."
RECURSIVE=0
MAX_DEPTH=0
NO_COUNT=0
NO_NESTED_COUNT=0
SORT_MODE="none"
declare -a EXCLUDE_PATTERNS=()
declare -a EXCLUDE_EXACT=()
declare -a TABLE_DATA=()
# Help
show_help() {
cat << 'EOF'
Usage: script [OPTIONS] [DIRECTORY]
Options:
-h, --help Показать эту справку
-r, --recursive Рекурсивно обойти все папки
-d, --depth LEVEL Глубина рекурсии (используется с -r)
--no-count Не считать объекты внутри папок
--no-nested-count Не показывать кол-во вложенных файлов/папок
-e, --exclude PATTERN Исключить файлы/папки (можно использовать несколько раз)
Поддерживает точные названия и паттерны (*, ?)
-s, --sort MODE Сортировка: az|za|up|down
az - по имени А→Я
za - по имени Я→А
up - по размеру ↑ (меньше→больше)
down - по размеру ↓ (больше→меньше)
Examples:
script .
script -r /path/to/dir
script -r -d 3 -e venv -e __pycache__ .
script -s up /path
script -e "*.pyc" -e "node_modules" .
EOF
}
# Определение типа файла и цвета
get_color() {
local file="$1"
# Если это директория
if [[ -d "$file" ]]; then
echo -e "${COLOR_YELLOW}"
return
fi
# Если исполняемый файл
if [[ -x "$file" && ! -d "$file" ]]; then
echo -e "${COLOR_GREEN}"
return
fi
# Проверяем расширение для аудио/видео
local ext="${file##*.}"
if [[ "$ext" =~ ^($AUDIO_VIDEO_EXTS)$ ]]; then
echo -e "${COLOR_CYAN}"
return
fi
# Для архивов и бинарников используем 'file'
local file_type=$(file -b "$file" 2>/dev/null)
if [[ "$file_type" =~ (archive|compressed|executable|ELF|PE32) ]]; then
echo -e "${COLOR_RED}"
return
fi
# По умолчанию белый для текста
echo -e "${COLOR_WHITE}"
}
# Проверка: нужно ли исключить файл
should_exclude() {
local name="$1"
# Проверяем точные названия
for pattern in "${EXCLUDE_EXACT[@]}"; do
if [[ "$name" == "$pattern" ]]; then
return 0
fi
done
# Проверяем паттерны
for pattern in "${EXCLUDE_PATTERNS[@]}"; do
if [[ "$name" == $pattern ]]; then
return 0
fi
done
return 1
}
# Подсчет объектов внутри папки
count_objects() {
local dir="$1"
local count=0
if [[ $NO_COUNT -eq 1 || $NO_NESTED_COUNT -eq 1 ]]; then
return
fi
# Считаем только прямых потомков
for item in "$dir"/*; do
[[ ! -e "$item" ]] && break
local base_name=$(basename "$item")
if ! should_exclude "$base_name"; then
((count++))
fi
done
if [[ $count -gt 0 ]]; then
echo "$count"
else
echo ""
fi
}
# Основная функция вывода
process_directory() {
local dir="$1"
local current_depth="${2:-0}"
local indent="${3:-}"
# Проверка глубины при рекурсии
if [[ $RECURSIVE -eq 1 && $MAX_DEPTH -gt 0 && $current_depth -ge $MAX_DEPTH ]]; then
return
fi
# Собираем список файлов
local -a items=()
for item in "$dir"/*; do
[[ ! -e "$item" && ! -L "$item" ]] && break
local base_name=$(basename "$item")
# Пропускаем исключённые
if should_exclude "$base_name"; then
continue
fi
items+=("$item")
done
# Сортируем если нужно
if [[ "$SORT_MODE" != "none" ]]; then
case "$SORT_MODE" in
az)
IFS=$'\n' items=($(sort <<<"${items[*]}"))
;;
za)
IFS=$'\n' items=($(sort -r <<<"${items[*]}"))
;;
up)
# Сортируем по размеру возрастающе
items=($(for item in "${items[@]}"; do
size=$(du -sh "$item" 2>/dev/null | cut -f1)
echo "$size|$item"
done | sort -V | cut -d'|' -f2-))
;;
down)
# Сортируем по размеру убывающе
items=($(for item in "${items[@]}"; do
size=$(du -sh "$item" 2>/dev/null | cut -f1)
echo "$size|$item"
done | sort -Vr | cut -d'|' -f2-))
;;
esac
fi
# Добавляем в таблицу
for item in "${items[@]}"; do
local base_name=$(basename "$item")
local color=$(get_color "$item")
local size=$(du -sh "$item" 2>/dev/null | cut -f1)
local nested_count=""
# Если папка, считаем объекты
if [[ -d "$item" ]]; then
nested_count=$(count_objects "$item")
fi
# Добавляем цветное имя для вывода
local colored_name="${color}${indent}${base_name}${COLOR_RESET}"
# Собираем данные для таблицы
TABLE_DATA+=("${colored_name}|${size}|${nested_count}")
# Рекурсия если флаг -r
if [[ $RECURSIVE -eq 1 && -d "$item" ]]; then
local new_indent="${indent} "
process_directory "$item" $((current_depth + 1)) "$new_indent"
fi
done
}
# Вывод таблицы
print_table() {
if [[ ${#TABLE_DATA[@]} -eq 0 ]]; then
echo "Директория пуста или не найдено файлов"
return
fi
# Заголовок таблицы
echo -e "\n${COLOR_WHITE}┌─────────────────────────────────────┬──────────┬──────────────┐"
printf "│ %-35s │ %-8s │ %-12s │\n" "Имя" "Размер" "Объектов"
echo -e "├─────────────────────────────────────┼──────────┼──────────────┤${COLOR_RESET}"
# Строки таблицы
for row in "${TABLE_DATA[@]}"; do
IFS='|' read -r name size nested <<< "$row"
# Очищаем ANSI коды для подсчета длины
local clean_name=$(echo -e "$name" | sed 's/\x1b\[[0-9;]*m//g')
local name_len=${#clean_name}
local padding=$((35 - name_len))
echo -ne "$name"
printf "%${padding}s │ %8s │ %12s │\n" "" "$size" "$nested"
done
echo -e "${COLOR_WHITE}└─────────────────────────────────────┴──────────┴──────────────┘${COLOR_RESET}\n"
}
# Парсинг аргументов
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
show_help
exit 0
;;
-r|--recursive)
RECURSIVE=1
shift
;;
-d|--depth)
MAX_DEPTH="$2"
shift 2
;;
--no-count)
NO_COUNT=1
shift
;;
--no-nested-count)
NO_NESTED_COUNT=1
shift
;;
-e|--exclude)
if [[ "$2" == *"*"* || "$2" == *"?"* ]]; then
EXCLUDE_PATTERNS+=("$2")
else
EXCLUDE_EXACT+=("$2")
fi
shift 2
;;
-s|--sort)
SORT_MODE="$2"
shift 2
;;
-*)
echo "Неизвестный флаг: $1" >&2
show_help
exit 1
;;
*)
DIRECTORY="$1"
shift
;;
esac
done
# Проверка что директория существует
if [[ ! -d "$DIRECTORY" ]]; then
echo "Ошибка: '$DIRECTORY' не является директорией" >&2
exit 1
fi
# Запуск
process_directory "$DIRECTORY"
# Вывод таблицы
print_table