===== Script Launcher =====
**Linux**\\
//**Проверено на Raspberry Pi4/5 OS**//\\
{{:niceos:launcher.png?nolink&|}}\\
Скрипт перебирает все скрипты ''*.sh'' в каталоге запуска и подкаталогах, если имеет доступ
и отбирают те в которых есть ''# ==AUTOEXEC==''
#!/bin/bash
# ==AUTOEXEC==
# === Название программы ===
# Строка для основного описания
# Строки для развернутого описания
# Строки для развернутого описания
#
строка для основного описания будет отображена следом за названием скрипта //***.sh**// через *
признаком окончания описания является первая первая найденная строка где кроме ''#'' ничего нет
==== Шаблон скрипта ====
Шаблон оформления скрипта для применения в лаунчере\\
Дополнительно сделан шаблон меню с выбором пунктов
++++Шаблон файла с заголовками для использования в лаунчере (нажмите чтобы раскрыть)|
#!/bin/bash
# ==AUTOEXEC==
# === Шаблон меню для нового скрипта ===
# * Основной шаблон bash-скрипта с пунктами меню и выходом по 0
# * Добавьте сюда свои действия и команды
#
PS3="📌 Выберите действие: "
echo " 0) ❌ Выход"
select action in "📂 Действие 1" "⚙️ Действие 2" "❌ Выход"; do
if [[ "$REPLY" == "0" ]]; then
echo "👋 До свидания!"
exit 0
fi
case $REPLY in
1)
echo "👉 Выполняем Действие 1"
# ваша команда здесь
;;
2)
echo "🔧 Выполняем Действие 2"
# ваша команда здесь
;;
3)
echo "👋 До свидания!"
exit 0
;;
*)
echo "❗ Неверный выбор";;
esac
break
done
exit 0
++++
===== Лаунчер =====
++++Лаунчер|
#!/bin/bash
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
# === 🚀Лаунчер ===
# ищет в основном каталоге и подкаталогах *
# файлы *.sh с ==AUTOEXEC== в шапке и создает список из таких файлов *
# с возможностью запуска *
# поддерживает режимы: включённые каталоги / исключённые каталоги *
# можно задавать глубину вложенности и абсолютные/относительные пути *
INCLUDE_MARKER="# ==AUTOEXEC=="
ROOT_DIR="$(pwd)"
TMP_LIST="/tmp/script_launcher_list.txt"
SELECTED_FILE=""
# Каталоги, которые нужно исключить (используются в режиме exclude)
EXCLUDE_DIRS=("scripts_arch" "backup_temp" "rpi_seal_arch")
# Каталоги, которые нужно включить (используются в режиме include)
INCLUDE_DIRS=("scripts" "rpi_seal")
# Глубина вложенности (0 = без ограничений)
MIN_DEPTH=0
MAX_DEPTH=0
# Режим поиска: include — искать только в указанных каталогах,
# exclude — искать везде, кроме исключённых
SEARCH_MODE="include"
# --- Проверка fzf ---
HAS_FZF=false
if command -v fzf &>/dev/null; then
HAS_FZF=true
fi
# --- Сбор скриптов (.sh) ---
> "$TMP_LIST"
SEPARATOR=" _ _ "
FIND_CONDITION=""
[[ "$MIN_DEPTH" -gt 0 ]] && FIND_CONDITION+=" -mindepth $MIN_DEPTH"
[[ "$MAX_DEPTH" -gt 0 ]] && FIND_CONDITION+=" -maxdepth $MAX_DEPTH"
if [[ "$SEARCH_MODE" == "include" ]]; then
for DIR in "${INCLUDE_DIRS[@]}"; do
[ -d "$DIR" ] || continue
find "$DIR" $FIND_CONDITION -type f -name "*.sh" 2>/dev/null
done
else
EXCLUDE_EXPR=""
for DIR in "${EXCLUDE_DIRS[@]}"; do
ABS_DIR=$(realpath "$DIR")
EXCLUDE_EXPR+=" -path \"$ABS_DIR\" -o"
done
EXCLUDE_EXPR="${EXCLUDE_EXPR::-3}"
eval "find \"$ROOT_DIR\" \( $EXCLUDE_EXPR \) -prune -o $FIND_CONDITION -type f -name \"*.sh\" -print" 2>/dev/null
fi | sort | while read -r FILE; do
if grep -q "^$INCLUDE_MARKER" "$FILE"; then
TITLE=""
SHORT=""
found_title=false
while IFS= read -r line; do
[[ -z "$line" ]] && break
if [[ "$line" =~ ^# ]]; then
CLEANED="${line#\# }"
if [[ "$CLEANED" =~ ^===.*=== ]]; then
TITLE="$(echo "$CLEANED" | sed -E 's/^=== *(.*?) *===$/\1/')"
found_title=true
elif [[ "$found_title" = true && -z "$SHORT" ]]; then
SHORT="$CLEANED"
fi
fi
done < <(tail -n +2 <(grep -A30 "^$INCLUDE_MARKER" "$FILE"))
TITLE=${TITLE:-"(Без названия)"}
DISPLAY_LINE="$TITLE"
[ -n "$SHORT" ] && DISPLAY_LINE+=" * $SHORT"
echo "$DISPLAY_LINE$SEPARATOR$FILE" >> "$TMP_LIST"
fi
done
if [ ! -s "$TMP_LIST" ]; then
echo "❌ Не найдено подходящих скриптов."
exit 1
fi
# --- Предпросмотр ---
PREVIEW_CMD=$(cat <<'EOF'
FILE=$(echo {} | awk -F " _ _ " '{print $2}')
if [ -f "$FILE" ]; then
ENCODING=$(file -bi "$FILE" | cut -d= -f2)
if [ "$ENCODING" != "utf-8" ]; then
echo "⚠️ Кодировка файла: $ENCODING (not UTF-8)"
echo "Могут быть проблемы с отображением."
echo ""
fi
BASENAME=$(basename "$FILE")
TITLE_LINE=$(awk '/^# ==AUTOEXEC==/{flag=1; next} /^$/{flag=0} flag && /^#/ && /===.*===/ { sub(/^# ?=== */, "", $0); sub(/ *===$/, "", $0); print; exit }' "$FILE")
echo -e "📄 $BASENAME\n📂 $FILE\n\n📛 $TITLE_LINE\n"
awk '/^# ==AUTOEXEC==/{flag=1; next} /^$/{flag=0} flag && /^#/ && !/===.*===/ { sub(/^# ?(\* )?/, "", $0); print }' "$FILE"
else
echo "❌ Файл не найден: $FILE"
fi
EOF
)
# --- Выбор интерфейса запуска ---
while true; do
echo "📦 Выберите режим запуска:"
echo " 1 - 🚀fzf-интерфейс $([ "$HAS_FZF" = true ] && echo "(доступен)" || echo "(недоступен)")"
echo " 2 - 📄Классическое текстовое меню"
echo " 0 - ❌Выход"
echo -n ">> "
read -r launcher_mode
case "$launcher_mode" in
1)
if [ "$HAS_FZF" = true ]; then
SELECTED_LINE=$(fzf --prompt="🚀 Выберите скрипт: " \
--delimiter="$SEPARATOR" \
--preview="$PREVIEW_CMD" \
--preview-window=right:60%:wrap \
< "$TMP_LIST")
if [ -z "$SELECTED_LINE" ]; then
echo "❎ Отмена пользователем."
rm -f "$TMP_LIST"
exit 0
fi
SELECTED_FILE=$(echo "$SELECTED_LINE" | awk -F "$SEPARATOR" '{print $2}' | xargs)
break
else
echo "⚠️ fzf не установлен. Установите с помощью:"
echo " sudo apt update && sudo apt install -y fzf"
launcher_mode=2
fi
;;
2)
echo "📜 Найденные скрипты:"
echo " 0) ❌ Выход"
echo
mapfile -t ENTRIES < <(awk -F "$SEPARATOR" '{print $1}' "$TMP_LIST")
ENTRIES+=("❌ Выход")
PS3="📌 Выберите скрипт: "
select ENTRY in "${ENTRIES[@]}"; do
if [[ "$REPLY" == "0" || "$ENTRY" == "❌ Выход" ]]; then
echo "👋 До свидания!"; rm -f "$TMP_LIST"; exit 0
fi
[ -z "$ENTRY" ] && echo "❌ Неверный выбор" && continue
SELECTED_FILE=$(grep -F "$ENTRY" "$TMP_LIST" | head -n1 | awk -F "$SEPARATOR" '{print $2}' | xargs)
break 2
done
;;
0)
echo "👋 До свидания!"
rm -f "$TMP_LIST"
exit 0
;;
*)
echo "❌ Неверный выбор"
;;
esac
done
# --- Подтверждение и запуск ---
echo "⚠️ Скрипт: $SELECTED_FILE"
echo "Запустить его? (y/N):"
read -r confirm
if [[ "$confirm" =~ ^[Yy]$ ]]; then
echo "🚀 Запуск..."
EXT="${SELECTED_FILE##*.}"
case "$EXT" in
sh) bash "$SELECTED_FILE" ;;
py) python3 "$SELECTED_FILE" ;;
*) echo "❌ Неизвестный тип файла: $EXT" ;;
esac
else
echo "❎ Отмена."
fi
rm -f "$TMP_LIST"
++++
===== Описание =====
++++script_launcher.md|
# 🚀 Лаунчер скриптов (версия V4)
**Дата создания:** 2025-04-05
## 📄 Описание
Этот Bash-скрипт выполняет поиск и запуск `.sh`-файлов, содержащих маркер `# ==AUTOEXEC==` в шапке. Он поддерживает два режима поиска:
- `exclude` — поиск от корня, исключая определённые каталоги.
- `include` — поиск только в явно указанных каталогах.
## ⚙️ Переменные настройки
| Переменная | Назначение |
|----------------|--------------------------------------------------------------------------------|
| `MODE` | Режим поиска: `auto` / `manual` (в этом варианте используется `exclude`) |
| `ROOT_DIR` | Корневая директория поиска в режиме `exclude` |
| `INCLUDE_DIRS` | Каталоги для поиска в режиме `include` (можно задать относительные/абсолютные) |
| `EXCLUDE_DIRS` | Каталоги, исключаемые из поиска |
| `MIN_DEPTH` | Минимальная глубина вложенности (0 — без ограничений) |
| `MAX_DEPTH` | Максимальная глубина вложенности (0 — без ограничений) |
| `SEPARATOR` | Разделитель между заголовком и путём в списке |
| `TMP_LIST` | Временный файл для хранения списка найденных скриптов |
## 🧩 Логика
1. Выполняется поиск `.sh`-файлов с учётом глубины и включений/исключений.
2. Извлекаются заголовок (`# === Название ===`) и краткое описание.
3. Создаётся список скриптов, отображаемый через:
- `fzf` (при наличии),
- или классическое Bash-меню.
4. Запуск выбранного скрипта с подтверждением.
## 🔍 Пример использования
Просто запустить:
```bash
./launcher.sh
```
## 🗂 Пример структуры проекта
```
project/
├── launcher.sh
├── scripts/
│ ├── backup.sh
│ ├── update.sh
├── scripts_arch/
│ └── old_backup.sh
```
## 🛡️ Советы
- Убедитесь, что скрипты имеют маркер `# ==AUTOEXEC==` и заголовок `# === Название ===`.
- Скрипт работает стабильно с абсолютными и относительными путями.
- Для предпросмотра `fzf` необходим пакет `fzf`.
++++
----
{{page>common:footer&noeditbutton}}