Перейти к содержимому

8. Bash скрипты

Bash скрипты — это автоматизация. Вместо того чтобы каждый раз вводить 10 команд вручную, ты пишешь скрипт и запускаешь его одной командой. Деплой, бэкапы, обработка данных — всё это делается через bash скрипты.

#!/bin/bash
# Первая строка — shebang: путь к интерпретатору
# Это обязательно для исполняемых скриптов
echo "Привет, мир!"
Окно терминала
# Создать и запустить
nano myscript.sh # или vim, или любой редактор
chmod +x myscript.sh # сделать исполняемым
./myscript.sh # запустить
# Или через bash напрямую (без chmod)
bash myscript.sh
#!/bin/bash
# Объявление переменных (без пробелов вокруг =!)
NAME="John"
AGE=30
GREETING="Привет"
# Использование переменных
echo "Меня зовут $NAME"
echo "Мне ${AGE} лет" # фигурные скобки для однозначности
echo "${GREETING}, ${NAME}!"
# Переменная из результата команды
CURRENT_DATE=$(date +%Y-%m-%d)
FILES_COUNT=$(ls -1 | wc -l)
echo "Дата: $CURRENT_DATE, файлов: $FILES_COUNT"
# Арифметика
A=10
B=3
SUM=$((A + B))
PRODUCT=$((A * B))
REMAINDER=$((A % B))
echo "Сумма: $SUM, произведение: $PRODUCT, остаток: $REMAINDER"
# Только для чтения
readonly CONFIG_DIR="/etc/myapp"
# Удалить переменную
unset NAME
#!/bin/bash
# Запуск: ./script.sh arg1 arg2 arg3
echo "Имя скрипта: $0"
echo "Первый аргумент: $1"
echo "Второй аргумент: $2"
echo "Все аргументы: $@"
echo "Количество аргументов: $#"
# Проверка аргументов
if [ $# -lt 2 ]; then
echo "Использование: $0 <имя> <возраст>"
exit 1
fi
echo "Привет, $1! Тебе $2 лет."
#!/bin/bash
AGE=25
# Числовые сравнения: -eq, -ne, -lt, -le, -gt, -ge
if [ $AGE -ge 18 ]; then
echo "Совершеннолетний"
elif [ $AGE -ge 14 ]; then
echo "Подросток"
else
echo "Ребёнок"
fi
# Строковые сравнения
NAME="admin"
if [ "$NAME" = "admin" ]; then
echo "Доступ разрешён"
fi
if [ "$NAME" != "guest" ]; then
echo "Не гость"
fi
# Проверка файлов и директорий
FILE="/etc/passwd"
if [ -f "$FILE" ]; then
echo "$FILE существует и является файлом"
fi
if [ -d "/home" ]; then
echo "/home — это директория"
fi
if [ -r "$FILE" ]; then
echo "Файл доступен для чтения"
fi
# Сложные условия
if [ $AGE -ge 18 ] && [ "$NAME" = "admin" ]; then
echo "Взрослый администратор"
fi
# [[ ]] — расширенный синтаксис (bash, не POSIX)
if [[ $NAME == adm* ]]; then # glob-паттерны
echo "Имя начинается с adm"
fi
if [[ $NAME =~ ^[a-z]+$ ]]; then # регулярные выражения
echo "Имя только из строчных букв"
fi
#!/bin/bash
# Цикл по списку
for NAME in Alice Bob Charlie; do
echo "Привет, $NAME!"
done
# Цикл по диапазону чисел
for i in {1..5}; do
echo "Итерация $i"
done
# Цикл with step
for i in {0..20..5}; do
echo $i # 0 5 10 15 20
done
# C-style цикл
for ((i=0; i<10; i++)); do
echo "i = $i"
done
# Цикл по файлам
for FILE in *.txt; do
echo "Обрабатываю: $FILE"
# wc -l "$FILE"
done
# Цикл по строкам файла
while IFS= read -r LINE; do
echo "Строка: $LINE"
done < input.txt
#!/bin/bash
# Цикл while
COUNT=1
while [ $COUNT -le 5 ]; do
echo "Итерация $COUNT"
COUNT=$((COUNT + 1))
done
# Чтение ввода пользователя
echo "Введите 'quit' для выхода:"
while true; do
read -p "> " INPUT
if [ "$INPUT" = "quit" ]; then
break
fi
echo "Ты ввёл: $INPUT"
done
# until — пока условие НЕ выполнено
COUNT=1
until [ $COUNT -gt 5 ]; do
echo "Count: $COUNT"
((COUNT++))
done
#!/bin/bash
# Объявление функции
greet() {
local NAME="$1" # local — переменная локальная для функции
local AGE="$2"
echo "Привет, $NAME! Тебе $AGE лет."
}
# Вызов функции
greet "Alice" 25
greet "Bob" 30
# Функция с возвращаемым значением
add() {
local A=$1
local B=$2
echo $((A + B)) # возвращаем через echo
}
RESULT=$(add 10 20)
echo "10 + 20 = $RESULT"
# Функция с кодом возврата
check_file() {
if [ -f "$1" ]; then
return 0 # успех
else
return 1 # ошибка
fi
}
if check_file "/etc/passwd"; then
echo "Файл существует"
else
echo "Файл не найден"
fi
#!/bin/bash
# $? — код возврата последней команды
ls /nonexistent 2>/dev/null
echo "Код возврата: $?" # 2 (ошибка)
ls /etc
echo "Код возврата: $?" # 0 (успех)
# set -e — прерывать скрипт при ошибке
set -e
# Проверка каждой команды
mkdir /tmp/mydir || { echo "Не удалось создать директорию"; exit 1; }
# trap — перехват сигналов и завершения
cleanup() {
echo "Очищаю временные файлы..."
rm -rf /tmp/myapp_*
}
trap cleanup EXIT # вызвать при любом выходе
trap cleanup INT TERM # вызвать при Ctrl+C
# Практический шаблон скрипта
set -euo pipefail # e=exit on error, u=undefined vars, o=pipe errors
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
log "Скрипт запущен"
log "Выполнено успешно"
#!/bin/bash
set -euo pipefail
# Конфигурация
SOURCE_DIR="${1:-$HOME}"
BACKUP_DIR="/tmp/backups"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE="${BACKUP_DIR}/backup_${DATE}.tar.gz"
# Функции
log() { echo "[$(date '+%H:%M:%S')] $1"; }
error() { echo "ОШИБКА: $1" >&2; exit 1; }
# Проверки
[ -d "$SOURCE_DIR" ] || error "Директория $SOURCE_DIR не существует"
mkdir -p "$BACKUP_DIR"
# Бэкап
log "Создаю бэкап $SOURCE_DIR..."
tar -czf "$ARCHIVE" "$SOURCE_DIR" 2>/dev/null
SIZE=$(du -sh "$ARCHIVE" | cut -f1)
log "Готово! Архив: $ARCHIVE ($SIZE)"
# Удалить бэкапы старше 7 дней
find "$BACKUP_DIR" -name "backup_*.tar.gz" -mtime +7 -delete
log "Старые бэкапы удалены"

Bash скрипты — твой первый шаг в автоматизацию. Начни с простых задач и постепенно усложняй!