Compare commits
2 Commits
4122afeda6
...
870548020d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
870548020d | ||
|
|
c7edca3c3e |
16
README.md
16
README.md
@@ -1,3 +1,19 @@
|
||||
# linux_tools
|
||||
|
||||
Инструменты для Линукс
|
||||
|
||||
использование всех инструментов: chmod +x combine.sh
|
||||
|
||||
# combine.sh
|
||||
Объединяет содержимое текстовых файлов из указанной директории в один файл. Удобно для подготовки контекста для AI, анализа кода или создания резюме проекта.
|
||||
|
||||
# finder.sh
|
||||
Утилита командной строки для анализа файлов в директории: сбор статистики по расширениям или отображение списка файлов с возможностью фильтрации и исключений
|
||||
|
||||
## Возможности
|
||||
|
||||
- Подсчёт количества файлов по расширениям с сортировкой
|
||||
- Фильтр по целевому расширению
|
||||
- Показ путей к файлам (режим `-p`)
|
||||
- Исключение директорий и отдельных расширений
|
||||
- Рекурсивный и нерекурсивный обход
|
||||
|
||||
215
combine.sh
Executable file
215
combine.sh
Executable file
@@ -0,0 +1,215 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Название выходного файла по умолчанию
|
||||
OUTPUT_FILE="combined_files.txt"
|
||||
# Директория по умолчанию
|
||||
INPUT_DIR="."
|
||||
# Флаги
|
||||
VERBOSE=0
|
||||
RECURSIVE=1
|
||||
# Массив для исключений
|
||||
EXCLUDE_PATHS=()
|
||||
|
||||
# Функция для показа помощи
|
||||
show_help() {
|
||||
echo "Использование: $0 [OPTIONS]"
|
||||
echo ""
|
||||
echo "Опции:"
|
||||
echo " -o, --output FILE Выходной файл (по умолчанию: combined_files.txt)"
|
||||
echo " -i, --input DIR Входная директория (по умолчанию: текущая)"
|
||||
echo " -e, --exclude PATH Исключить путь (можно указать несколько раз)"
|
||||
echo " -r, --recursive Рекурсивный поиск (включено по умолчанию)"
|
||||
echo " -n, --no-recursive Не рекурсивный поиск"
|
||||
echo " -v, --verbose Подробный вывод"
|
||||
echo " -h, --help Показать эту справку"
|
||||
echo ""
|
||||
echo "Примеры:"
|
||||
echo " $0 -v -o result.txt"
|
||||
echo " $0 -i ~/projects -o /tmp/combined.txt"
|
||||
echo " $0 -e venv -e foto -e node_modules"
|
||||
echo " $0 --no-recursive --verbose -e temp"
|
||||
}
|
||||
|
||||
# Парсинг аргументов командной строки
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-o|--output)
|
||||
OUTPUT_FILE="$2"
|
||||
shift 2
|
||||
;;
|
||||
-i|--input)
|
||||
INPUT_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
-e|--exclude)
|
||||
EXCLUDE_PATHS+=("$2")
|
||||
shift 2
|
||||
;;
|
||||
-r|--recursive)
|
||||
RECURSIVE=1
|
||||
shift
|
||||
;;
|
||||
-n|--no-recursive)
|
||||
RECURSIVE=0
|
||||
shift
|
||||
;;
|
||||
-v|--verbose)
|
||||
VERBOSE=1
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Ошибка: Неизвестный параметр $1"
|
||||
echo "Используйте $0 --help для справки"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Проверка существования входной директории
|
||||
if [[ ! -d "$INPUT_DIR" ]]; then
|
||||
echo "Ошибка: Директория '$INPUT_DIR' не существует"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Проверка на запись в выходной файл
|
||||
if touch "$OUTPUT_FILE" 2>/dev/null; then
|
||||
rm -f "$OUTPUT_FILE"
|
||||
else
|
||||
echo "Ошибка: Нет прав для записи в '$OUTPUT_FILE'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Запоминаем текущую директорию для возврата
|
||||
CURRENT_DIR="$(pwd)"
|
||||
|
||||
# Переход в входную директорию если она указана не как текущая
|
||||
if [[ "$INPUT_DIR" != "." ]]; then
|
||||
cd "$INPUT_DIR" || {
|
||||
echo "Ошибка: Не удалось перейти в директорию '$INPUT_DIR'"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
# Очищаем выходной файл
|
||||
> "$OUTPUT_FILE"
|
||||
|
||||
# Счетчики
|
||||
total_files=0
|
||||
processed_files=0
|
||||
skipped_files=0
|
||||
|
||||
# Вывод информации о запуске
|
||||
if [[ $VERBOSE -eq 1 ]]; then
|
||||
echo "Запуск combine.sh с параметрами:"
|
||||
echo " Входная директория: $(pwd)"
|
||||
echo " Выходной файл: $OUTPUT_FILE"
|
||||
echo " Рекурсивный поиск: $([[ $RECURSIVE -eq 1 ]] && echo 'Да' || echo 'Нет')"
|
||||
if [[ ${#EXCLUDE_PATHS[@]} -gt 0 ]]; then
|
||||
echo " Исключения: ${EXCLUDE_PATHS[*]}"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Функция для обработки файлов
|
||||
process_files() {
|
||||
local find_cmd="find . -type f"
|
||||
|
||||
# Если не рекурсивно, ищем только в текущей директории
|
||||
if [[ $RECURSIVE -eq 0 ]]; then
|
||||
find_cmd="find . -maxdepth 1 -type f"
|
||||
fi
|
||||
|
||||
# Добавляем стандартные исключения
|
||||
find_cmd="$find_cmd \
|
||||
-not -path \"./venv/*\" \
|
||||
-not -path \"*/venv/*\" \
|
||||
-not -path \"*/__pycache__/*\" \
|
||||
-not -path \"*cache*\" \
|
||||
-not -path \"*.pyc\" \
|
||||
-not -path \"db.*\" \
|
||||
-not -path \"*.lock\" \
|
||||
-not -path \"*.git/*\" \
|
||||
-not -path \"*.db\" \
|
||||
-not -path \"*.pack\" \
|
||||
-not -path \"*/node_modules/*\" \
|
||||
-not -path \"./$OUTPUT_FILE\""
|
||||
|
||||
# Добавляем пользовательские исключения
|
||||
for exclude in "${EXCLUDE_PATHS[@]}"; do
|
||||
# Убираем начальные ./ если есть
|
||||
exclude="${exclude#./}"
|
||||
find_cmd="$find_cmd -not -path \"./$exclude\" -not -path \"./$exclude/*\" -not -path \"*/$exclude/*\""
|
||||
done
|
||||
|
||||
find_cmd="$find_cmd 2>/dev/null"
|
||||
|
||||
# Временный файл для результатов find
|
||||
local temp_file=$(mktemp)
|
||||
|
||||
# Выполняем поиск и сохраняем во временный файл
|
||||
eval "$find_cmd" > "$temp_file"
|
||||
|
||||
# Обрабатываем файлы
|
||||
while IFS= read -r file; do
|
||||
[[ -z "$file" ]] && continue
|
||||
|
||||
((total_files++))
|
||||
|
||||
# Пропускаем бинарные файлы
|
||||
if file "$file" | grep -q "text"; then
|
||||
# Получаем относительный путь файла
|
||||
relative_path="${file#./}"
|
||||
|
||||
if [[ $VERBOSE -eq 1 ]]; then
|
||||
echo "Добавляем: $relative_path"
|
||||
fi
|
||||
|
||||
# Добавляем разделитель с именем файла в выходной файл
|
||||
{
|
||||
echo "# ========================================="
|
||||
echo "# Файл: $relative_path"
|
||||
echo "# ========================================="
|
||||
echo ""
|
||||
cat "$file" 2>/dev/null
|
||||
echo ""
|
||||
echo ""
|
||||
} >> "$OUTPUT_FILE"
|
||||
|
||||
((processed_files++))
|
||||
else
|
||||
if [[ $VERBOSE -eq 1 ]]; then
|
||||
echo "Пропускаем (бинарный): ${file#./}"
|
||||
fi
|
||||
((skipped_files++))
|
||||
fi
|
||||
done < "$temp_file"
|
||||
|
||||
# Удаляем временный файл
|
||||
rm -f "$temp_file"
|
||||
}
|
||||
|
||||
# Запускаем обработку
|
||||
process_files
|
||||
|
||||
# Возвращаемся в исходную директорию если нужно
|
||||
if [[ "$INPUT_DIR" != "." ]]; then
|
||||
cd "$CURRENT_DIR" || exit 1
|
||||
fi
|
||||
|
||||
# Итоговый отчет
|
||||
echo "Готово!"
|
||||
echo "Обработано файлов: $processed_files из $total_files"
|
||||
if [[ $skipped_files -gt 0 ]]; then
|
||||
echo "Пропущено бинарных файлов: $skipped_files"
|
||||
fi
|
||||
if [[ ${#EXCLUDE_PATHS[@]} -gt 0 ]]; then
|
||||
echo "Исключено путей: ${#EXCLUDE_PATHS[@]}"
|
||||
fi
|
||||
echo "Результат в: $OUTPUT_FILE"
|
||||
if [[ "$INPUT_DIR" != "." ]]; then
|
||||
echo "Исходная директория: $INPUT_DIR"
|
||||
fi
|
||||
254
finder.sh
Executable file
254
finder.sh
Executable file
@@ -0,0 +1,254 @@
|
||||
#!/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
|
||||
Reference in New Issue
Block a user