Files
linux_tools/finder.sh
2026-05-12 18:24:43 +03:00

255 lines
9.2 KiB
Bash
Executable File
Raw 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
# Флаги
VERBOSE=0
SHOW_PATHS=0
RECURSIVE=1
TARGET_EXT=""
INPUT_DIR="."
NO_DEFAULT_EXCLUDES=0
EXCLUDE_DIRS=()
EXCLUDE_EXTS=()
# Функция помощи
show_help() {
echo "Использование: $0 [OPTIONS] [EXTENSION]"
echo ""
echo "Опции:"
echo " -i, --input DIR Входная директория (по умолчанию текущая)"
echo " -v, --verbose Подробный вывод"
echo " -p, --paths Показать пути к файлам (вместо статистики)"
echo " -n, --no-recursive Только текущая директория"
echo " -r, --recursive Рекурсивный обход (по умолчанию)"
echo " -e, --exclude-dir DIR Исключить директорию (можно несколько раз)"
echo " --exclude-ext EXT Исключить расширение файла (можно несколько раз)"
echo " -D, --no-default-excludes Не исключать .git (по умолчанию .git исключается)"
echo " -h, --help Показать эту справку"
echo ""
echo "Примеры:"
echo " $0 # Статистика всех файлов"
echo " $0 .txt # Статистика txt файлов"
echo " $0 -p .py # Показать все пути к .py файлам"
echo " $0 -p # Показать пути ко всем файлам"
echo " $0 -v # Подробная статистика всех файлов"
echo " $0 -n # Только в текущей директории"
echo " $0 -e build --exclude-ext log # Исключить папку build и .log файлы"
echo " $0 -D # Отключить встроенное исключение .git"
echo " $0 -i ~/projects -p .py # Показать .py файлы в указанной папке"
}
# Парсинг аргументов
while [[ $# -gt 0 ]]; do
case $1 in
-v|--verbose)
VERBOSE=1
shift
;;
-p|--paths)
SHOW_PATHS=1
shift
;;
-r|--recursive)
RECURSIVE=1
shift
;;
-n|--no-recursive)
RECURSIVE=0
shift
;;
-i|--input)
if [[ -z "$2" ]]; then
echo "Ошибка: опция -i требует аргумент"
exit 1
fi
INPUT_DIR="$2"
shift 2
;;
-e|--exclude-dir)
if [[ -z "$2" ]]; then
echo "Ошибка: опция -e требует аргумент"
exit 1
fi
EXCLUDE_DIRS+=("$2")
shift 2
;;
--exclude-ext)
if [[ -z "$2" ]]; then
echo "Ошибка: опция --exclude-ext требует аргумент"
exit 1
fi
EXCLUDE_EXTS+=("$2")
shift 2
;;
-D|--no-default-excludes)
NO_DEFAULT_EXCLUDES=1
shift
;;
-h|--help)
show_help
exit 0
;;
-*)
echo "Ошибка: Неизвестная опция $1"
show_help
exit 1
;;
*)
TARGET_EXT="$1"
shift
;;
esac
done
# Проверка существования входной директории
if [[ ! -d "$INPUT_DIR" ]]; then
echo "Ошибка: Директория '$INPUT_DIR' не существует"
exit 1
fi
# Переход в рабочую директорию
CURRENT_DIR="$(pwd)"
cd "$INPUT_DIR" || {
echo "Ошибка: Не удалось перейти в директорию '$INPUT_DIR'"
exit 1
}
WORK_DIR="$(pwd)"
# Очистка расширения: убираем ведущую точку, если есть
clean_ext() {
local ext="$1"
ext="${ext#.}"
echo "$ext"
}
# Функция получения расширения файла (без точки)
get_extension() {
local file="$1"
local filename=$(basename -- "$file")
local ext="${filename##*.}"
if [[ "$ext" == "$filename" ]]; then
echo "no_extension"
else
echo "$ext"
fi
}
# Основная функция поиска и вывода
process_files() {
# Построение массива аргументов для find
local find_args=(".")
local has_target=0
# Глубина
if [[ $RECURSIVE -eq 0 ]]; then
find_args+=("-maxdepth" "1")
fi
# Только файлы
find_args+=("-type" "f")
# Стандартные исключения (только .git)
if [[ $NO_DEFAULT_EXCLUDES -eq 0 ]]; then
find_args+=("-not" "-path" "./.git/*" "-not" "-path" "./.git")
fi
# Пользовательские исключения директорий
for dir in "${EXCLUDE_DIRS[@]}"; do
dir="${dir%/}" # убрать слеш в конце
local clean_dir="${dir#./}"
# Исключаем саму директорию и всё внутри неё
find_args+=("-not" "-path" "./$clean_dir" "-not" "-path" "./$clean_dir/*")
# На всякий случай, если вложена где-то ещё
find_args+=("-not" "-path" "*/$clean_dir/*" "-not" "-path" "*/$clean_dir")
done
# Фильтр по целевому расширению
if [[ -n "$TARGET_EXT" ]]; then
has_target=1
if [[ "$TARGET_EXT" == "no_extension" ]]; then
find_args+=("!" "-name" "*.*")
else
local ext_clean=$(clean_ext "$TARGET_EXT")
find_args+=("-name" "*.$ext_clean")
fi
fi
# Исключение расширений
for ext in "${EXCLUDE_EXTS[@]}"; do
ext=$(clean_ext "$ext")
find_args+=("-not" "-name" "*.$ext")
done
# Вывод информации при verbose
if [[ $VERBOSE -eq 1 ]]; then
echo "Рабочая директория: $WORK_DIR"
echo "Режим: $([[ $SHOW_PATHS -eq 1 ]] && echo 'Показ путей' || echo 'Статистика')"
echo "Рекурсивно: $([[ $RECURSIVE -eq 1 ]] && echo 'Да' || echo 'Нет')"
echo "Стандартные исключения: $([[ $NO_DEFAULT_EXCLUDES -eq 0 ]] && echo '.git' || echo 'Нет')"
[[ -n "$TARGET_EXT" ]] && echo "Целевое расширение: $TARGET_EXT"
[[ ${#EXCLUDE_DIRS[@]} -gt 0 ]] && echo "Исключаемые папки: ${EXCLUDE_DIRS[*]}"
[[ ${#EXCLUDE_EXTS[@]} -gt 0 ]] && echo "Исключаемые расширения: ${EXCLUDE_EXTS[*]}"
echo ""
fi
if [[ $SHOW_PATHS -eq 1 ]]; then
# Режим вывода путей
if [[ -n "$TARGET_EXT" ]]; then
echo "Пути к .$(clean_ext "$TARGET_EXT") файлам:"
else
echo "Пути ко всем файлам:"
fi
echo "=========================="
local count=0
while IFS= read -r -d '' file; do
echo "${file#./}"
((count++))
done < <(find "${find_args[@]}" -print0 2>/dev/null)
echo "-------------------------"
echo "Найдено файлов: $count"
else
# Режим статистики
declare -A stats
while IFS= read -r -d '' file; do
local ext
if [[ -n "$TARGET_EXT" ]]; then
ext=$(clean_ext "$TARGET_EXT")
else
ext=$(get_extension "$file")
fi
((stats["$ext"]++))
done < <(find "${find_args[@]}" -print0 2>/dev/null)
if [[ -n "$TARGET_EXT" ]]; then
local t=$(clean_ext "$TARGET_EXT")
echo "Статистика .$t файлов:"
echo "============================="
echo "$t: ${stats[$t]:-0}"
else
echo "Статистика файлов:"
echo "================="
local total_files=0
# Сортировка расширений по убыванию количества
for ext in "${!stats[@]}"; do
printf "%s %d\n" "$ext" "${stats[$ext]}"
done | sort -k2 -nr | while read ext count; do
printf "%-15s %d\n" "$ext" "$count"
done
# Суммируем (цикл выше в подоболочке, поэтому считаем отдельно)
for count in "${stats[@]}"; do
((total_files += count))
done
echo "-------------------------"
echo "Всего файлов: $total_files"
echo "Уникальных расширений: ${#stats[@]}"
fi
fi
}
# Запуск обработки
process_files
# Возврат в исходную директорию
if [[ "$CURRENT_DIR" != "$WORK_DIR" ]]; then
cd "$CURRENT_DIR" || exit 1
fi