Загрузка данных
1. lib/common-colors.sh
Это базовый модуль. Его нужно подключать первым.
#!/usr/bin/env bash
# ═══════════════════════════════════════════════════════════════
# Общие цвета и функции вывода
#
# Используется другими модулями:
# - check-root.sh
# - ensure-executable.sh
# - set-locale.sh
# - ask-yes-no.sh
# - ask-reboot.sh
#
# Подключение:
#
# source "${SCRIPT_DIR}/lib/common-colors.sh"
# ═══════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════
# Основные цвета
# ═══════════════════════════════════════════════════════════════
RD=$(echo "\033[01;31m")
YW=$(echo "\033[33m")
GN=$(echo "\033[1;92m")
BL=$(echo "\033[1;34m")
CL=$(echo "\033[m")
# ═══════════════════════════════════════════════════════════════
# Дополнительные цвета
# ═══════════════════════════════════════════════════════════════
GREEN="\e[32m"
RED="\e[31m"
YELLOW="\e[33m"
BLUE="\e[34m"
NC="\e[0m"
# ═══════════════════════════════════════════════════════════════
# Символы
# ═══════════════════════════════════════════════════════════════
BFR="\\r\\033[K"
HOLD="-"
CM="${GN}✓${CL}"
CROSS="${RD}✗${CL}"
ARROW="${BL}➜${CL}"
# ═══════════════════════════════════════════════════════════════
# Информационное сообщение
# ═══════════════════════════════════════════════════════════════
msg_info() {
local msg="$1"
echo -ne " ${HOLD} ${YW}${msg}..."
}
# ═══════════════════════════════════════════════════════════════
# Успешное выполнение
# ═══════════════════════════════════════════════════════════════
msg_ok() {
local msg="$1"
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
}
# ═══════════════════════════════════════════════════════════════
# Ошибка
# ═══════════════════════════════════════════════════════════════
msg_error() {
2. lib/check-root.sh
#!/usr/bin/env bash
# ═══════════════════════════════════════════════════════════════
# Проверка прав root
#
# Функция:
#
# check_root
#
# Проверяет, запущен ли основной скрипт
# с правами суперпользователя root.
#
# Требует:
#
# common-colors.sh
#
# потому что используется msg_error().
# ═══════════════════════════════════════════════════════════════
check_root() {
# EUID — эффективный UID текущего пользователя.
#
# UID 0 = root.
#
# Если EUID не равен 0,
# скрипт запущен не от root.
if [[ $EUID -ne 0 ]]; then
# Выводим сообщение об ошибке.
msg_error "Скрипт требует прав root!"
# Показываем пользователю,
# как перейти в root.
echo -e " ${YW}Запустите от root:${CL} su -"
# Завершаем выполнение программы.
exit 1
fi
}
3. lib/ensure-executable.sh
#!/usr/bin/env bash
# ═══════════════════════════════════════════════════════════════
# Проверка права на выполнение
#
# Функция:
#
# ensure_executable "/путь/к/файлу.sh"
#
# Проверяет:
#
# 1. Передан ли путь к файлу.
# 2. Существует ли файл.
# 3. Имеет ли файл право на выполнение (+x).
#
# Если +x отсутствует — автоматически выполняется:
#
# chmod +x
#
# Требует:
#
# common-colors.sh
#
# для msg_info() и msg_ok().
# ═══════════════════════════════════════════════════════════════
ensure_executable() {
# Получаем путь к файлу из первого аргумента.
local target="${1:-}"
# ═══════════════════════════════════════════════════════════
# Проверка аргумента
# ═══════════════════════════════════════════════════════════
if [ -z "$target" ]; then
echo "ensure_executable: не указан файл" >&2
return 1
fi
# ═══════════════════════════════════════════════════════════
# Проверка существования файла
# ═══════════════════════════════════════════════════════════
if [ ! -e "$target" ]; then
echo "ensure_executable: файл не найден: $target" >&2
return 1
fi
# ═══════════════════════════════════════════════════════════
# Проверка права +x
# ═══════════════════════════════════════════════════════════
# Если файл уже исполняемый,
# ничего менять не требуется.
if [ -x "$target" ]; then
return 0
fi
# ═══════════════════════════════════════════════════════════
# Проверка root
# ═══════════════════════════════════════════════════════════
# Для изменения прав файла
# необходимы соответствующие права.
if [ "$(id -u)" -ne 0 ]; then
echo "ensure_executable: нужны права root (chmod +x)" >&2
echo " Запустите: su - или sudo $0 $target" >&2
return 1
fi
# ═══════════════════════════════════════════════════════════
# Добавление права +x
# ═══════════════════════════════════════════════════════════
if declare -F msg_info >/dev/null 2>&1; then
msg_info "Файл не исполняемый, добавляем права (+x)"
4. lib/ask-yes-no.sh
Это универсальный модуль для вопросов y/n.
#!/usr/bin/env bash
# ═══════════════════════════════════════════════════════════════
# Запрос да/нет
#
# Использование:
#
# ask_yes_no "Продолжить? (y/n): "
#
# Возвращает:
#
# 0 — пользователь ответил Y/y
# 1 — любой другой ответ
#
#
# Также доступна функция:
#
# ask_confirm_or_exit
#
# При отказе завершает основной скрипт.
#
# Требует:
#
# common-colors.sh
# ═══════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════
# Проверяем наличие msg_ok
# ═══════════════════════════════════════════════════════════════
if ! declare -F msg_ok >/dev/null 2>&1; then
_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "${_LIB_DIR}/common-colors.sh"
unset _LIB_DIR
fi
# ═══════════════════════════════════════════════════════════════
# Запрос Y/N
# ═══════════════════════════════════════════════════════════════
ask_yes_no() {
# Текст вопроса является обязательным аргументом.
local prompt="${1:?ask_yes_no: нужен текст вопроса}"
local answer
# Читаем ответ пользователя.
read -r -p "$prompt" answer
# Проверяем ответ.
case "$answer" in
# Y или y — положительный ответ.
[Yy]*)
return 0
;;
# Любой другой ответ — отрицательный.
*)
return 1
;;
esac
}
# ═══════════════════════════════════════════════════════════════
# Подтверждение или выход
# ═══════════════════════════════════════════════════════════════
ask_confirm_or_exit() {
# Вопрос по умолчанию.
local prompt="${1:-Продолжить установку? (y/n): }"
# Если пользователь согласился —
# продолжаем выполнение.
if ask_yes_no "$prompt"; then
return 0
fi
# Если пользователь отказался —
# сообщаем об отмене.
msg_ok "Отменено пользователем"
# Завершаем основной скрипт.
exit 0
}
5. lib/ask-reboot.sh
Теперь перезагрузка тоже отдельным модулем.
#!/usr/bin/env bash
# ═══════════════════════════════════════════════════════════════
# Запрос на перезагрузку
#
# Использование:
#
# ask_reboot
#
# Перезагрузка через 5 секунд.
#
#
# Можно указать собственную задержку:
#
# ask_reboot 10
#
# В этом случае перезагрузка произойдёт
# через 10 секунд.
#
# Требует:
#
# common-colors.sh
# ask-yes-no.sh
# ═══════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════
# Подключение common-colors.sh
# ═══════════════════════════════════════════════════════════════
if ! declare -F msg_info >/dev/null 2>&1; then
_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "${_LIB_DIR}/common-colors.sh"
unset _LIB_DIR
fi
# ═══════════════════════════════════════════════════════════════
# Подключение ask-yes-no.sh
# ═══════════════════════════════════════════════════════════════
if ! declare -F ask_yes_no >/dev/null 2>&1; then
_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "${_LIB_DIR}/ask-yes-no.sh"
unset _LIB_DIR
fi
# ═══════════════════════════════════════════════════════════════
# Запрос на перезагрузку
# ═══════════════════════════════════════════════════════════════
ask_reboot() {
# Первый аргумент — задержка перед перезагрузкой.
#
# Если аргумент не передан,
# используется 5 секунд.
local delay="${1:-5}"
# Спрашиваем пользователя.
if ask_yes_no "Перезагрузить систему сейчас? (y/n): "; then
# Показываем обратный отсчёт.
msg_info "Перезагрузка через ${delay} секунд"
# Небольшая задержка.
sleep "$delay"
# Перезагружаем систему.
reboot
else
# Если пользователь отказался.
msg_ok "Не забудьте перезагрузить систему позже!"
fi
}
6. lib/set-locale.sh
Здесь находится только логика русификации.
#!/usr/bin/env bash
# ═══════════════════════════════════════════════════════════════
# Русификация Kali Linux
#
# Функция:
#
# set_locale
#
# Выполняет:
#
# 1. Проверку пакета locales.
# 2. Установку locales при необходимости.
# 3. Включение ru_RU.UTF-8.
# 4. Генерацию локали.
# 5. Установку ru_RU.UTF-8 по умолчанию.
#
# Перезагрузка здесь НЕ выполняется.
#
# За перезагрузку отвечает:
#
# ask-reboot.sh
# ═══════════════════════════════════════════════════════════════
set_locale() {
# ═══════════════════════════════════════════════════════════
# Проверка пакета locales
# ═══════════════════════════════════════════════════════════
msg_info "Проверяем пакет locales"
if ! dpkg -s locales >/dev/null 2>&1; then
msg_info "Пакет locales не установлен"
# Обновляем список пакетов.
apt update
# Устанавливаем locales.
apt install -y locales
msg_ok "Пакет locales установлен"
else
msg_ok "Пакет locales уже установлен"
fi
# ═══════════════════════════════════════════════════════════
# Настройка ru_RU.UTF-8
# ═══════════════════════════════════════════════════════════
msg_info "Настраиваем ru_RU.UTF-8"
# Проверяем, закомментирована ли русская локаль.
if grep -q '^# *ru_RU.UTF-8 UTF-8' /etc/locale.gen; then
# Убираем # перед ru_RU.UTF-8.
sed -i \
's/^# *ru_RU.UTF-8 UTF-8/ru_RU.UTF-8 UTF-8/' \
/etc/locale.gen
# Если строки нет вообще —
# добавляем её.
elif ! grep -q '^ru_RU.UTF-8 UTF-8' /etc/locale.gen; then
echo 'ru_RU.UTF-8 UTF-8' >> /etc/locale.gen
fi
# ═══════════════════════════════════════════════════════════
# Генерация локали
# ═══════════════════════════════════════════════════════════
msg_info "Генерируем ru_RU.UTF-8"
7. russification.sh
И наконец, главный файл. Именно его запускаешь ты.
#!/usr/bin/env bash
# ═══════════════════════════════════════════════════════════════
# Kali Linux — Русификация
#
# Главный скрипт.
#
# Запуск:
#
# ./russification.sh
#
# Или:
#
# bash russification.sh
#
# Для работы требуются права root.
# ═══════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════
# Определяем директорию проекта
# ═══════════════════════════════════════════════════════════════
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# ═══════════════════════════════════════════════════════════════
# Подключение библиотек
# ═══════════════════════════════════════════════════════════════
#
# Порядок важен:
#
# 1. common-colors.sh
# 2. check-root.sh
# 3. ensure-executable.sh
# 4. ask-yes-no.sh
# 5. ask-reboot.sh
# 6. set-locale.sh
#
# ═══════════════════════════════════════════════════════════════
# Общие цвета и функции вывода.
# shellcheck disable=SC1091
source "${SCRIPT_DIR}/lib/common-colors.sh"
# Проверка root.
# shellcheck disable=SC1091
source "${SCRIPT_DIR}/lib/check-root.sh"
# Проверка прав +x.
# shellcheck disable=SC1091
source "${SCRIPT_DIR}/lib/ensure-executable.sh"
# Запросы Y/N.
# shellcheck disable=SC1091
source "${SCRIPT_DIR}/lib/ask-yes-no.sh"
# Запрос перезагрузки.
# shellcheck disable=SC1091
source "${SCRIPT_DIR}/lib/ask-reboot.sh"
# Русификация.
# shellcheck disable=SC1091
source "${SCRIPT_DIR}/lib/set-locale.sh"
# ═══════════════════════════════════════════════════════════════
# Проверка root
# ═══════════════════════════════════════════════════════════════
check_root
# ═══════════════════════════════════════════════════════════════
# Проверка прав на выполнение
# ═══════════════════════════════════════════════════════════════
ensure_executable "${SCRIPT_DIR}/russification.sh"
ensure_executable "${SCRIPT_DIR}/lib/common-colors.sh"
# ═══════════════════════════════════════════════════════════════
ask_reboot 5
В итоге
Структура:
kali-russification/
│
├── russification.sh ← ЗАПУСКАЕШЬ ЭТОТ
│
└── lib/
│
├── common-colors.sh ← цвета / сообщения
│
├── check-root.sh ← проверка root
│
├── ensure-executable.sh ← проверка +x
│
├── ask-yes-no.sh ← вопросы y/n
│
├── ask-reboot.sh ← запрос перезагрузки
│
└── set-locale.sh ← русификация