===== Script Launcher =====
**Linux**
Скрипты далее перебирают все скрипты ''*.sh'' в каталоге запуска и подкаталогах, если имеет доступ
и отбирают те в которых есть ''# ==AUTOEXEC==''
#!/bin/bash
# ==AUTOEXEC==
# === Название программы ===
# * Строка для основного описания
# * Строки для развернутого описания
# * Строки для развернутого описания
# //строка ниже служит для обозначения окончания описания
#
признаком окончания описания является первая первая найденная строка где кроме ''#'' ничего нет
==== Шаблон скрипта ====
Шаблон оформления скрипта для применения в лаунчере\\
Дополнительно сделан шаблон меню с выбором пунктов
++++Шаблон файла с заголовками для использования в лаунчере (нажмите чтобы раскрыть)|
#!/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
++++
==== Лаунчер скриптов (с оболочкой fzf) ====
При запуске можно выбрать fzf меню или средствами bash скрипта
Еслы был выбор fzf но он не установлен, запустится выбор через bash скрипт
++++Скрипт для поиска и запуска скрптов из подкаталогов при помощи утилиты fzf (нажмите чтобы раскрыть)|
#!/bin/bash
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
INCLUDE_MARKER="# ==AUTOEXEC=="
ROOT_DIR="$(pwd)"
TMP_LIST="/tmp/script_launcher_list.txt"
SELECTED_FILE=""
# --- Проверка fzf ---
HAS_FZF=false
if command -v fzf &>/dev/null; then
HAS_FZF=true
fi
# --- Сбор скриптов (.sh и .py 'по умолчанию отключено') ---
> "$TMP_LIST"
find "$ROOT_DIR" -type f -name "*.sh" | while read -r FILE; do
if grep -q "^$INCLUDE_MARKER" "$FILE"; then
TITLE=""
SHORT=""
while IFS= read -r line; do
[[ -z "$line" ]] && break
if [[ "$line" =~ ^# ]]; then
CLEANED="${line#\# }"
if [[ "$CLEANED" =~ ^===.*=== ]]; then
TITLE="$CLEANED"
elif [[ "$CLEANED" =~ ^\* ]]; then
SHORT="${CLEANED#\* }"
fi
fi
done < <(tail -n +2 <(grep -A30 "^$INCLUDE_MARKER" "$FILE"))
DISPLAY_LINE="$(basename "$FILE") :: $TITLE * $SHORT"
echo -e "$DISPLAY_LINE|$FILE" >> "$TMP_LIST"
fi
done
if [ ! -s "$TMP_LIST" ]; then
echo "❌ Не найдено подходящих скриптов."
exit 1
fi
# --- Выбор интерфейса запуска ---
while true; do
echo "\n📦 Выберите режим запуска:"
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=$(cat "$TMP_LIST" | \
fzf --prompt="🚀 Выберите скрипт: " \
--preview='FILE=$(echo {} | cut -d"|" -f2); \
[ -f "$FILE" ] && awk "/^# ==AUTOEXEC==/{flag=1; next} /^$/{flag=0} flag && /^#/ { sub(/^# ?/, \"\", \$0); print }" "$FILE" || echo "❌ Файл не найден: $FILE"' \
--preview-window=right:60%:wrap)
if [ -z "$SELECTED_LINE" ]; then
echo "❎ Отмена пользователем."
rm -f "$TMP_LIST"
exit 0
fi
SELECTED_FILE=$(echo "$SELECTED_LINE" | cut -d'|' -f2)
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 < <(cut -d'|' -f1 "$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 | cut -d'|' -f2)
break 2
done
;;
0)
echo "👋 До свидания!"
rm -f "$TMP_LIST"
exit 0
;;
*)
echo "❌ Неверный выбор"
;;
esac
done
# --- Подтверждение и запуск ---
echo "\n⚠️ Скрипт: $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"
++++
===== Ver 2 =====
++++Лаунчер|
#!/bin/bash
# Устанавливаем локаль, чтобы fzf и вывод работали корректно
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
# Маркер, по которому определяется, что скрипт можно запускать из меню
INCLUDE_MARKER="# ==AUTOEXEC=="
# Текущий рабочий каталог, откуда начнётся поиск
ROOT_DIR="$(pwd)"
# Создаём уникальный временный файл для хранения списка скриптов
TMP_LIST=$(mktemp /tmp/script_launcher_list.XXXXXX)
# Удалим временный файл при завершении скрипта — в любом случае
trap "rm -f '$TMP_LIST'" EXIT
# Переменная для хранения выбранного файла
SELECTED_FILE=""
# --- Проверка наличия fzf ---
HAS_FZF=false
if command -v fzf &>/dev/null; then
HAS_FZF=true
fi
# --- Сбор скриптов (.sh; поддержка .py отключена по умолчанию) ---
> "$TMP_LIST"
find "$ROOT_DIR" -type f -name "*.sh" | while read -r FILE; do
if grep -q "^$INCLUDE_MARKER" "$FILE"; then
TITLE=""
SHORT=""
# Чтение заголовка и краткого описания из комментариев после маркера
while IFS= read -r line; do
[[ -z "$line" ]] && break
if [[ "$line" =~ ^# ]]; then
CLEANED="${line#\# }"
if [[ "$CLEANED" =~ ^===.*=== ]]; then
TITLE="$CLEANED"
elif [[ "$CLEANED" =~ ^\* ]]; then
SHORT="${CLEANED#\* }"
fi
fi
done < <(tail -n +2 <(grep -A30 "^$INCLUDE_MARKER" "$FILE"))
DISPLAY_LINE="$(basename "$FILE") :: $TITLE * $SHORT"
echo -e "$DISPLAY_LINE|$FILE" >> "$TMP_LIST"
fi
done
# Если список скриптов пуст — выходим
if [ ! -s "$TMP_LIST" ]; then
echo "❌ Не найдено подходящих скриптов."
exit 1
fi
# --- Выбор интерфейса запуска ---
while true; do
echo -e "\n📦 Выберите режим запуска:"
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
# fzf с предпросмотром описания из скрипта
SELECTED_LINE=$(cat "$TMP_LIST" | \
fzf --prompt="🚀 Выберите скрипт: " \
--preview='FILE=$(echo {} | cut -d"|" -f2); \
[ -f "$FILE" ] && awk "/^# ==AUTOEXEC==/{flag=1; next} /^$/{flag=0} flag && /^#/ { sub(/^# ?/, \"\", \$0); print }" "$FILE" || echo "❌ Файл не найден: $FILE"' \
--preview-window=right:60%:wrap)
# Отмена выбора
if [ -z "$SELECTED_LINE" ]; then
echo "❎ Отмена пользователем."
exit 0
fi
SELECTED_FILE=$(echo "$SELECTED_LINE" | cut -d'|' -f2)
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 < <(cut -d'|' -f1 "$TMP_LIST")
ENTRIES+=("❌ Выход")
PS3="📌 Выберите скрипт: "
select ENTRY in "${ENTRIES[@]}"; do
if [[ "$REPLY" == "0" || "$ENTRY" == "❌ Выход" ]]; then
echo "👋 До свидания!"
exit 0
fi
[ -z "$ENTRY" ] && echo "❌ Неверный выбор" && continue
SELECTED_FILE=$(grep -F "$ENTRY" "$TMP_LIST" | head -n1 | cut -d'|' -f2)
break 2
done
;;
0)
echo "👋 До свидания!"
exit 0
;;
*)
echo "❌ Неверный выбор"
;;
esac
done
# --- Подтверждение и запуск ---
echo -e "\n⚠️ Скрипт: $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
++++
===== Описание =====
# Script Launcher
Утилита для запуска локальных скриптов с использованием системы тегов и интерфейса выбора. Поддерживает интерактивный выбор через `fzf` (если установлен) или текстовое меню. Разрабатывается для работы в рамках одного каталога, ориентирована на читаемость и безопасность.
---
## 📦 Возможности
- Поиск всех `.sh`-файлов в текущем каталоге
- Отбор скриптов только с маркером `# ==AUTOEXEC==`
- Чтение заголовка (вида `# === Название ===`) и краткого описания (`# * краткое описание`)
- Поддержка интерфейса выбора через `fzf` с предпросмотром описания
- Альтернатива — классическое текстовое меню Bash
- Подтверждение перед запуском
- Поддержка временных файлов через `mktemp` с автоудалением (`trap`)
---
## 🔧 Требования
- Bash 4+
- [fzf](https://github.com/junegunn/fzf) (опционально, для интерактивного режима)
Установка fzf:
```bash
sudo apt update && sudo apt install -y fzf
```
---
## 🧠 Структура
Скрипты должны содержать специальную метку `# ==AUTOEXEC==`, за которой идут комментарии с описанием:
```bash
# ==AUTOEXEC==
# === Название скрипта ===
# * Краткое описание или цель
```
Пример:
```bash
# ==AUTOEXEC==
# === Сохранить резервную копию ===
# * Создаёт .tar.gz архив с логированием
```
---
## 🚀 Запуск
Сначала выполните `launcher.sh` из нужного каталога:
```bash
bash launcher.sh
```
- У меня настроен алиас на высов скрипта 'lll', мне кажется так удобнее
Выберите интерфейс:
1. fzf-интерфейс (если доступен)
2. Классическое меню
0. Выход
Выбранный скрипт запускается **только после подтверждения**.
---
## 🔐 Безопасность и устойчивость
- Временные файлы создаются через `mktemp`, исключая конфликты при параллельном запуске
- Удаляются автоматически через `trap EXIT`
- Нет выполнения кода без согласия пользователя
- Нет внешних сетевых обращений
---
## 📁 Планы на будущее
- Опциональная поддержка `.py`-файлов
- Флаги запуска (`--py`, `--no-preview` и т.п.)
- Категории или теги
- Логирование запусков
---
Дата обновления: 26.03.2025