package linuxmodules import ( "fmt" "rubric/utils" ) var ScriptsModule = Module{ Key: "scripts", Aliases: []string{"sc", "scripting", "скрипты"}, Title: "Bash-скрипты", Description: "Темы 27–32: скрипты, условия, циклы, функции, массивы", Run: showScripts, } func showScripts() { utils.Header("Linux — Bash-скрипты") // ─── 27. Bash скрипты №1 ────────────────────────────────────── utils.Section("27. Основы скриптов. Условия") utils.Println(utils.ColorBold + "Структура скрипта:" + utils.ColorReset) utils.Code(`#!/bin/bash # Shebang — первая строка указывает интерпретатор # Комментарий echo "Привет, мир!" # Запуск скрипта: chmod +x script.sh # сделать исполняемым ./script.sh # запустить bash script.sh # запустить через bash (без chmod)`) utils.Println(utils.ColorBold + "Переменные в скриптах:" + utils.ColorReset) utils.Code(`#!/bin/bash name="Alice" count=5 echo "Имя: $name" echo "Счёт: $count" # Ввод от пользователя: read -p "Введите имя: " username echo "Привет, $username!" # Ввод без отображения (пароль): read -s -p "Пароль: " password`) utils.Println(utils.ColorBold + "Условный оператор if:" + utils.ColorReset) utils.Code(`#!/bin/bash # Базовая форма: if [ условие ]; then команды elif [ другое_условие ]; then команды else команды fi # Примеры условий: # Сравнение строк: if [ "$name" = "Alice" ]; then echo "Привет, Alice"; fi if [ "$name" != "Bob" ]; then echo "Не Боб"; fi if [ -z "$name" ]; then echo "Пустая строка"; fi # -z = пусто if [ -n "$name" ]; then echo "Не пустая"; fi # -n = не пусто # Сравнение чисел: if [ "$count" -eq 5 ]; then ... # equal if [ "$count" -ne 5 ]; then ... # not equal if [ "$count" -gt 3 ]; then ... # greater than if [ "$count" -lt 10 ]; then ... # less than if [ "$count" -ge 5 ]; then ... # greater or equal if [ "$count" -le 5 ]; then ... # less or equal # Файлы и директории: if [ -f /etc/passwd ]; then echo "файл существует"; fi if [ -d /tmp ]; then echo "директория существует"; fi if [ -e /dev/sda ]; then echo "путь существует"; fi if [ -r file ]; then echo "доступен для чтения"; fi if [ -w file ]; then echo "доступен для записи"; fi if [ -x script.sh ]; then echo "исполняемый"; fi if [ -s file ]; then echo "файл не пустой"; fi if [ file1 -nt file2 ]; then echo "file1 новее"; fi # Логика: if [ cond1 ] && [ cond2 ]; then ... # И if [ cond1 ] || [ cond2 ]; then ... # ИЛИ if ! [ cond ]; then ... # НЕ # [[ ]] — расширенные условия bash: if [[ "$str" == *"подстрока"* ]]; then ... # glob if [[ "$str" =~ ^[0-9]+$ ]]; then ... # regex`) // ─── 28–29. Bash скрипты №2–3 ───────────────────────────────── utils.Section("28–29. Циклы") utils.Println(utils.ColorBold + "Цикл for:" + utils.ColorReset) utils.Code(`# По списку: for item in один два три; do echo "$item" done # По числовому диапазону: for i in {1..5}; do echo "Шаг $i" done # С шагом: for i in {0..20..5}; do echo "$i"; done # 0 5 10 15 20 # C-стиль: for ((i=0; i<5; i++)); do echo "$i" done # По файлам: for file in /etc/*.conf; do echo "Обрабатываю: $file" done # По строкам вывода команды: for user in $(cat /etc/passwd | cut -d: -f1); do echo "Пользователь: $user" done`) utils.Println(utils.ColorBold + "Цикл while:" + utils.ColorReset) utils.Code(`# Пока условие истинно: count=0 while [ $count -lt 5 ]; do echo "count = $count" ((count++)) done # Чтение файла построчно: while IFS= read -r line; do echo "Строка: $line" done < /etc/hosts # Бесконечный цикл: while true; do echo "Работаю..." sleep 1 done`) utils.Println(utils.ColorBold + "Цикл until и управление циклами:" + utils.ColorReset) utils.Code(`# Пока условие ложно: until [ -f /tmp/ready ]; do echo "Жду файл..." sleep 1 done # break — выйти из цикла: for i in {1..10}; do if [ $i -eq 5 ]; then break; fi echo $i done # continue — перейти к следующей итерации: for i in {1..10}; do if [ $((i % 2)) -eq 0 ]; then continue; fi echo "Нечётное: $i" done`) // ─── 30–31. Bash скрипты №4–5 ───────────────────────────────── utils.Section("30–31. Функции и обработка ошибок") utils.Println(utils.ColorBold + "Функции:" + utils.ColorReset) utils.Code(`#!/bin/bash # Объявление функции: greet() { local name=$1 # local — локальная переменная echo "Привет, $name!" } # Или: function greet { echo "Привет, $1!" } # Вызов: greet "Alice" greet "Bob" # Возвращаемое значение: # Функции возвращают только числа (код возврата 0-255) is_root() { [ "$(id -u)" -eq 0 ] } if is_root; then echo "Запущен как root" fi # Для передачи строк — echo + подстановка команд: get_hostname() { echo "$(hostname)" } host=$(get_hostname)`) utils.Println(utils.ColorBold + "Обработка ошибок:" + utils.ColorReset) utils.Code(`#!/bin/bash # Остановить при ошибке: set -e # выйти при любой ошибке (exit on error) set -u # ошибка при неопределённой переменной set -o pipefail # учитывать ошибки в pipe set -euo pipefail # всё вместе (рекомендуется) # Проверка кода возврата: if ! mkdir /tmp/mydir 2>/dev/null; then echo "Ошибка создания директории" >&2 exit 1 fi # Функция для вывода ошибок: error() { echo "ОШИБКА: $*" >&2 exit 1 } [ -f "$1" ] || error "Файл $1 не найден" # Trap — обработка сигналов и выхода: cleanup() { rm -f /tmp/tempfile echo "Очищено" } trap cleanup EXIT # при любом выходе trap cleanup INT TERM # при Ctrl+C или kill`) // ─── 32. Bash скрипты №6 ────────────────────────────────────── utils.Section("32. Массивы, строки и аргументы скрипта") utils.Println(utils.ColorBold + "Массивы:" + utils.ColorReset) utils.Code(`# Объявление: fruits=("яблоко" "банан" "апельсин") declare -a numbers=(1 2 3 4 5) # Доступ: echo "${fruits[0]}" # яблоко (индекс с 0) echo "${fruits[@]}" # все элементы echo "${#fruits[@]}" # количество элементов echo "${fruits[@]:1:2}" # срез: с индекса 1, 2 элемента # Добавить элемент: fruits+=("манго") # Перебор: for fruit in "${fruits[@]}"; do echo "$fruit" done # Перебор с индексом: for i in "${!fruits[@]}"; do echo "$i: ${fruits[$i]}" done # Ассоциативный массив (словарь): declare -A user user[name]="Alice" user[age]=30 echo "${user[name]}" echo "${!user[@]}" # ключи echo "${user[@]}" # значения`) utils.Println(utils.ColorBold + "Аргументы скрипта:" + utils.ColorReset) utils.Code(`#!/bin/bash # Позиционные параметры: echo "Скрипт: $0" echo "Первый аргумент: $1" echo "Второй аргумент: $2" echo "Все аргументы: $@" echo "Количество аргументов: $#" # Проверка аргументов: if [ $# -lt 2 ]; then echo "Использование: $0 <имя> <возраст>" >&2 exit 1 fi # Обработка опций (getopts): while getopts "hv:n:" opt; do case $opt in h) echo "Справка"; exit 0 ;; v) verbose=true ;; n) name="$OPTARG" ;; ?) echo "Неизвестный ключ"; exit 1 ;; esac done # shift — сдвинуть аргументы: shift $((OPTIND - 1)) # убрать опции, остались обычные аргументы`) utils.Println(utils.ColorBold + "Полезные приёмы:" + utils.ColorReset) utils.Code(`# Цвета в терминале: RED='\033[0;31m' GREEN='\033[0;32m' NC='\033[0m' # No Color echo -e "${RED}Ошибка${NC}" echo -e "${GREEN}Успех${NC}" # Прогресс-бар простой: for i in {1..10}; do echo -ne "\rПрогресс: $((i*10))%" sleep 0.1 done; echo # Логирование: LOG=/var/log/myscript.log log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG"; } log "Скрипт запущен" # Ожидание с таймаутом: timeout 30 ./long_command.sh || echo "Таймаут!"`) fmt.Println() utils.Note("Проверяйте скрипты на ошибки: bash -n script.sh (синтаксис) и bash -x script.sh (трассировка).") utils.Footer() }