Практически любая рутинная задача на Linux-сервере – резервное копирование, работа с логами, перезапуск сервисов, обработка файлов – может выполняться автоматически. Инструмент, который это позволяет, называется Bash-скрипт. Это обычный текстовый файл со списком команд, которые система выполняет одну за другой.
В этой статье разберем основы Bash: что это за оболочка, как устроен синтаксис скриптов, как работать с переменными, условиями, циклами и функциями, а также как запускать скрипты на сервере. Все примеры можно повторить на любом Linux-сервере с доступом по SSH – например, на VPS от Beget.
Что такое Bash
Bash (Bourne Again Shell) – это командная оболочка (shell), то есть программа-посредник между пользователем и ядром операционной системы. Вы вводите текстовую команду, Bash ее разбирает, запускает нужную программу и показывает результат.
Bash появился в 1989 году как развитие более старой оболочки sh (Bourne Shell) и с тех пор он установлен по умолчанию в большинстве дистрибутивов Linux: Ubuntu, Debian, CentOS, AlmaLinux и других. Когда вы подключаетесь к серверу по SSH и видите приглашение вида user@server:~$, это именно командная оболочка Bash.
Оболочка работает в двух режимах:
- интерактивный – вы вводите команды вручную по одной и сразу видите результат;
- скриптовый – команды заранее записаны в файл, оболочка выполняет их последовательно без вашего участия.
Второй режим и есть то, ради чего пишут скрипты: один раз описать последовательность действий и выполнять ее сколько угодно раз.
Проверить, какая оболочка используется у вас, можно командой:
echo $0А узнать версию Bash – так:
bash --versionЧем Bash отличается от sh, zsh и других оболочек
В Linux существует несколько оболочек, и путаница между ними – источник трудноуловимых ошибок в скриптах. Разберем самые популярные:
sh– минималистичная POSIX-оболочка. Скрипты максимально переносимы, но многих удобных возможностей нет. В Debian и Ubuntu/bin/sh– это симлинк наdash, а не наbash;bash– в основном совместим с POSIX-sh, но добавляет много собственных возможностей. Скрипты, написанные с учетом этого стандарта, будут исполняться без изменений в любых системах, поддерживающих POSIX;zsh– мощная и гибкая оболочка, поддерживающая темы и плагины. Используется по умолчанию в macOS. Полной POSIX-совместимости уzshнет, хотя большинство Bash-скриптов выполняются без изменений. При необходимостиzshможет запускаться в режимеsh, а синтаксис во многом пересекается сbash;fish– в отличие отbashиzsh, изначально создавалась как оболочка, ориентированная на удобство, но не совместимая с POSIX. Поэтому скрипты, написанные дляbashилиzsh, как правило, не будут исполняться, их нужно адаптировать подfish.
#!/bin/bash, запускайте его командой bash script.sh или ./script.sh, но не sh script.sh – во втором случае скрипт выполнит другая оболочка, что может повлечь ошибки.Для чего используют Bash-скрипты
Bash-скрипты применяют везде, где нужна автоматизация на уровне операционной системы:
- резервное копирование. Скрипт архивирует каталог с сайтом и дамп базы данных, складывает архив в отдельную папку и удаляет копии старше 30 дней;
- обслуживание сервера. Очистка временных файлов и логов, ротация архивов, контроль свободного места на диске;
- мониторинг. Проверка доступности сайта, состояния служб, нагрузки на CPU и память с отправкой уведомления при отклонении от нормы;
- развертывание проектов. Установка зависимостей, сборка приложения, миграции базы данных, перезапуск сервисов – все одной командой;
- массовая обработка файлов. Переименование, конвертация, поиск и замена текста в сотнях файлов;
- настройка окружения. Файлы
.bashrcи.bash_profileпозволяют задать переменные окружения, псевдонимы (алиасы) и вид приглашения командной строки; - связывание утилит через конвейеры.
bashпередает вывод одной программы на вход другой, что позволяет собирать сложные обработки данных из простых команд.
Основные команды Bash


Синтаксис Bash-скриптов
Bash-скрипт – это обычный текстовый файл. Создать его можно в любом редакторе:
nano– самый простой вариант для новичка: подсказки по горячим клавишам всегда внизу экрана, сохранение сочетанием клавишCtrl+Oи выход поCtrl+X;vim– мощный редактор с модальным управлением, подсветкой синтаксиса и макросами, но требует времени на освоение.
Расширение .sh для скриптов не обязательно, но общепринято – оно помогает быстро понять назначение файла.
Шебанг
Первая строка скрипта называется шебанг (shebang) и указывает системе, какой интерпретатор использовать. Она начинается с символов #!, за которыми следует путь к интерпретатору:
#!/bin/bashТакже можно явно указать путь к интерпретатору. Может быть полезна, если на разных системах bash лежит в разных каталогах:
#!/usr/bin/env bashКомментарии
Всё, что идет после символа # (кроме шебанга), интерпретатор игнорирует. Комментарии описывают логику скрипта и не влияют на выполнение:
#!/bin/bash
# Этот скрипт выводит приветствие
echo "Привет!" # комментарий можно писать и в конце строкиКавычки
Кавычки – то место, где чаще всего можно допустить ошибку:
"текст $var"– двойные кавычки: переменные и команды подставляются;'текст $var'– одинарные кавычки: всё воспринимается буквально, подстановки нет;`команда`или`$(команда)`– подстановка результата выполнения команды.
Пример:
#!/bin/bash
name="Beget"
echo "Привет, $name" # Привет, Beget
echo 'Привет, $name' # Привет, $name
echo "Дата: $(date +%F)" # Дата: 2026-07-24"$file", а не `$file` – иначе имя файла с пробелом bash разделит на несколько аргументов, и скрипт сработает не так, как задумано.Как создать и запустить Bash-скрипт
- В первую очередь необходимо создать файл:
touch hello.sh- Откройте файл любым текстовым редактором, впишите код и сохраните файл:
#!/bin/bash
echo "Hello, World!"- Сделайте файл исполняемым. По умолчанию новый файл не имеет права на выполнение. Его нужно выдать командой
chmod:
chmod +x hello.shОбщий синтаксис команды:
chmod [опции] права файлПрава можно задавать двумя способами:
- символьным (
+x,u+rw) - числовым (
700,644)
Несколько примеров:
755–rwxr-xr-x– владелец может всё, остальные – читать и выполнять700–rwx------– доступ только владельцу644–rw-r--r--– обычный файл без права на выполнение
- Запуск скрипта. Есть три способа:
./hello.sh– запуск как программы, нужен бит выполнения и шебангbash hello.sh– явный запуск через интерпретатор, бит выполнения не нуженsource hello.sh– выполнение в текущей оболочке (или короткая форма:. hello.sh)
При запуске с помощью source скрипт выполняется не в отдельном процессе, а в текущей сессии, поэтому заданные в нем переменные останутся доступны после завершения. Именно так подключают файлы конфигурации.
./ bash будет искать hello.sh только в каталогах из переменной PATH и выдаст ошибку command not found.Переменные
Переменные хранят данные: строки, числа, результаты выполнения команд.
Создание и использование
Переменная создается оператором присваивания =.
= недопустимы.#!/bin/bash
host="beget.com" # правильно
# host = "beget.com" # ошибка: command not foundЧтобы получить значение, перед именем ставится символ $. Форма с фигурными скобками ${host} нужна, когда сразу после имени идет другой текст:
echo "$host"
echo "${host}_backup" # без скобок Bash искал бы переменную host_backupВвод данных от пользователя
Команда read считывает строку с клавиатуры и записывает ее в переменную:
#!/bin/bash
read -p "Введите ваше имя: " username
echo "Здравствуйте, $username!"Параметр -p выводит приглашение, а -s скрывает ввод – это удобно при запросе пароля.
Переменные окружения
Часть переменных система задает автоматически. Полный список выводит команда env:
$HOME– домашний каталог пользователя;$USER– имя текущего пользователя;$PWD– текущий рабочий каталог;$PATH– список каталогов, где ищутся исполняемые файлы;$SHELL– путь к текущей оболочке;$HOSTNAME– имя хоста.
Чтобы переменная стала доступна дочерним процессам, ее экспортируют:
export API_KEY="secret"Арифметика
Bash по умолчанию работает со строками, поэтому арифметику заключают в двойные круглые скобки:
#!/bin/bash
a=10
b=3
echo $(( a + b )) # 13
echo $(( a * b )) # 30
echo $(( a / b )) # 3 - целочисленное деление
echo $(( a % b )) # 1 - остатокДля дробных чисел встроенных средств нет, используется утилита bc:
echo "scale=2; 10 / 3" | bc # 3.33Параметры командной строки
Скрипту можно передавать аргументы при запуске – внутри они доступны через позиционные переменные $1, $2, $3 и так далее.
#!/bin/bash
echo "Привет, $1! Тебе $2 лет."Запуск:
./greet.sh Иван 30
# Привет, Иван! Тебе 30 лет.Помимо позиционных, есть специальные переменные:
$0– имя самого скрипта;$#– количество переданных аргументов;$@– все аргументы как отдельные элементы (используйте"$@");$*– все аргументы одной строкой;$?– код возврата последней команды:0– успех, любое другое число – ошибка;$$– PID текущего процесса.
Условные операторы
Условия позволяют скрипту принимать решения.
Конструкция if
if [ условие ]; then
команды
elif [ другое_условие ]; then
команды
else
команды
fiОбратите внимание на пробелы внутри квадратных скобок – [ $a -eq $b ]. Без них bash выдаст ошибку, потому что [ – это не синтаксический элемент, а самостоятельная команда.
Сравнение чисел
-eq– равно;-ne– не равно;-gt– больше;-ge– больше или равно;-lt– меньше;-le– меньше или равно.
Сравнение строк
=или==– строки равны;!=– строки не равны;-z– строка пустая;-n– строка не пустая.
Проверка файлов
-e– файл или каталог существует;-f– существует и является обычным файлом;-d– существует и является каталогом;-r/-w/-x– доступен для чтения / записи / выполнения;-s– существует и не пустой.
Пример:
#!/bin/bash
file="/var/log/nginx/error.log"
if [ -f "$file" ]; then
echo "Файл найден, размер: $(du -h "$file" | cut -f1)"
else
echo "Файл $file не найден"
exit 1
fiЛогические операторы
Условия комбинируются через && (И), || (ИЛИ) и ! (отрицание):
#!/bin/bash
age=25
if [ "$age" -ge 18 ] && [ "$age" -lt 65 ]; then
echo "Возраст в рабочем диапазоне"
fi
if [ ! -d "/backup" ]; then
mkdir -p /backup
fiВ Bash вместо одинарных скобок удобнее использовать двойные [[ ]]: они безопаснее при работе с переменными, поддерживают шаблоны и логику &&/|| внутри скобок:
if [[ "$filename" == *.txt && -f "$filename" ]]; then
echo "Это текстовый файл"
fiКонструкция case
Когда вариантов много, case читается лучше длинной цепочки elif:
#!/bin/bash
case "$1" in
start)
echo "Запуск сервиса"
;;
stop)
echo "Остановка сервиса"
;;
restart)
echo "Перезапуск сервиса"
;;
*)
echo "Использование: $0 {start|stop|restart}"
exit 1
;;
esacЦиклы
Циклы выполняют один и тот же блок команд многократно.
Цикл for
Перебирает элементы списка:
#!/bin/bash
for number in 1 2 3 4 5; do
echo "Итерация $number"
doneДиапазон удобнее записывать через фигурные скобки:
for i in {1..10}; do
echo "$i"
doneПеребор файлов в каталоге – одна из самых частых задач:
#!/bin/bash
for file in /var/log/*.log; do
echo "Обрабатываю: $file"
gzip "$file"
doneЦикл while
Выполняется, пока условие остается истинным:
#!/bin/bash
counter=1
while [ "$counter" -le 5 ]; do
echo "Счетчик: $counter"
counter=$(( counter + 1 ))
doneТипичный прием – построчное чтение файла:
#!/bin/bash
while read -r line; do
echo "Строка: $line"
done < /etc/hostsЦикл until
Противоположность while – выполняется, пока условие ложно, и останавливается, когда оно станет истинным.
#!/bin/bash
count=1
until [ "$count" -gt 3 ]; do
echo "Попытка $count"
count=$(( count + 1 ))
donebreak и continue
break досрочно выходит из цикла, continue пропускает текущую итерацию:
#!/bin/bash
for i in {1..10}; do
if [ "$i" -eq 5 ]; then
continue # пропускаем пятерку
fi
if [ "$i" -gt 8 ]; then
break # выходим из цикла
fi
echo "$i"
doneФункции
Функции группируют команды в именованные блоки, которые можно вызывать многократно. Это избавляет от дублирования кода.
Объявление
Два равнозначных варианта:
my_function() {
команды
}
# или
function my_function {
команды
}Функцию нужно объявить до первого вызова – bash читает скрипт сверху вниз.
Аргументы
Аргументы передаются через пробел после имени функции, без круглых скобок и запятых. Внутри они доступны как $1, $2 и так далее:
#!/bin/bash
greet() {
echo "Привет, $1! Тебе $2 лет."
}
greet "Анна" 30Локальные переменные и возврат значений
По умолчанию все переменные в bash глобальные. Чтобы переменная существовала только внутри функции, она объявляется с ключевым словом local – это защищает от неожиданной перезаписи данных:
#!/bin/bash
calculate() {
local result=$(( $1 + $2 ))
echo "$result" # «возврат» значения через вывод
}
sum=$(calculate 5 7)
echo "Сумма: $sum" # Сумма: 12Оператор return в Bash возвращает код завершения (число от 0 до 255), а не значение. Чтобы вернуть данные, их выводят через echo и перехватывают подстановкой $( ):
#!/bin/bash
check_file() {
if [ -f "$1" ]; then
return 0 # успех
else
return 1 # ошибка
fi
}
if check_file "/etc/passwd"; then
echo "Файл существует"
fiМассивы
Массив хранит набор значений под одним именем:
#!/bin/bash
servers=("web1" "web2" "db1")
echo "${servers[0]}" # web1 - нумерация с нуля
echo "${servers[@]}" # все элементы
echo "${#servers[@]}" # количество элементов: 3
servers+=("cache1") # добавить элемент
for server in "${servers[@]}"; do
echo "Проверяю $server"
doneРабота с файлами и директориями
Проверить существование файла можно командой test или ее краткой формой – квадратными скобками:
test -e filename
# то же самое:
[ -e filename ]Команда возвращает 0, если файл существует, и ненулевое значение в противном случае. Результат доступен в переменной $?.
Несколько типовых операций:
#!/bin/bash
# Создать каталог, если его нет
mkdir -p /backup/2026
# Скопировать с сохранением прав и меток времени
cp -a /var/www/site /backup/site
# Найти и удалить файлы старше 30 дней
find /backup -name "*.tar.gz" -mtime +30 -delete
# Посчитать количество строк в файле
lines=$(wc -l < /var/log/access.log)
echo "Строк в логе: $lines"
# Создать архив
tar -czf /backup/site-$(date +%Y-%m-%d).tar.gz /var/www/siteПеренаправление потоков и конвейеры
У каждой программы в Linux есть три стандартных потока: ввод (stdin, дескриптор 0), вывод (stdout, 1) и вывод ошибок (stderr, 2). Bash позволяет ими управлять:
команда > file– записать вывод в файл, перезаписав его;команда >> file– записать вывод в конец файла;команда 2> file– записать в файл только ошибки;команда > file 2>&1– записать в файл и вывод, и ошибки;команда > /dev/null 2>&1– полностью подавить любой вывод;команда1 | команда2– передать вывод первой команды на вход второй.
Конвейер (pipe) используются для связи нескольких команд путем перенаправления вывода одной команды (stdout) на вход (stdin) последующей, используя символ конвейера |.
# Топ-10 IP-адресов по количеству запросов в логе nginx
cat /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10Запуск скриптов по расписанию через cron
Для запуска скрипта, который нужно выполнять регулярно, используется планировщик cron:
crontab -eСинтаксис для добавления задания через терминал: минута час день месяц день_недели команда. Пример:
# Каждый день в 03:30 запускать резервное копирование
30 3 * * * /home/user/scripts/backup.sh >> /home/user/logs/backup.log 2>&1На виртуальном хостинге Beget задания cron удобнее настраивать через раздел CronTab в панели управления.
Отладка скриптов
Пошаговый режим показывает каждую команду перед выполнением с подставленными значениями переменных:
bash -x script.shВнутри скрипта отладку можно включать и выключать для отдельного участка:
set -x # включить трассировку
# проблемный код
set +x # выключитьЕще один прием, который может быть полезен, – “строгий режим” в начале каждого скрипта:
#!/bin/bash
set -euo pipefail-e– прервать выполнение при первой же ошибке;-u– считать ошибкой обращение к необъявленной переменной;-o pipefail– возвращать ошибку, если сбой произошел в любом звене конвейера.
Без этих настроек скрипт после неудачной команды продолжит работу как ни в чем не бывало. Например, попытается заархивировать каталог, который не удалось создать.
Для проверки синтаксиса без запуска используйте:
bash -n script.shА для полноценного анализа кода – утилиту ShellCheck:
apt install shellcheck # Debian/Ubuntu
shellcheck script.shПрактические примеры скриптов
Резервное копирование сайта и базы данных
#!/bin/bash
# Количество дней для хранения копий
days=14
# Путь к папке с файлами для хранения файлов копий
backup_dir="backups"
# Имя директории сайта
site_dir="yoursite.com"
# Имя базы данных
db_name="login_db"
# Пароль для доступа к базе данных
db_pass="Mpo2Dkm"
d=`date +%F-%H:%M:%S`
mkdir -p $backup_dir 2>/dev/null
# Удаление старых файлов копий
find $backup_dir -name "*autobackup.tar.gz" -type f -mtime +$days -delete
# Дамп базы данных
dump_name="$site_dir/dump-$d.sql"
mysqldump -h localhost -u$db_name $db_name -p"$db_pass" > $dump_name
# Архивирование файлов
tar cvvzf "$backup_dir/$site_dir-$d-autobackup.tar.gz" $site_dir
rm $dump_nameПроверка доступности сайта
#!/bin/bash
URL="https://example.com"
code=$(curl -o /dev/null -s -w "%{http_code}" --max-time 10 "$URL")
if [ "$code" -ne 200 ]; then
echo "[$(date)] $URL недоступен, код ответа: $code" >> /var/log/site-check.log
else
echo "[$(date)] $URL работает нормально"
fiFAQ
«Permission denied»?У файла нет бита выполнения. Выполните chmod +x script.sh. Если ошибка сохраняется, проверьте, что раздел не смонтирован с опцией noexec.
./script.sh и source script.sh?Первый вариант запускает скрипт в отдельном процессе – изменения переменных не сохранятся в вашей сессии. Второй выполняет команды в текущей оболочке, поэтому переменные и функции останутся доступны после завершения.
Да, это возможно, но установка пакетов и настройка системных служб доступны на VPS и выделенных серверах, где вы работаете с правами root.
Bash идеален для последовательного вызова системных утилит и работы с файлами: то, что в Python занимает десяток строк с импортами, здесь помещается в одну. Но как только появляются сложные структуры данных, работа с API или объемная логика, читаемость Bash резко падает – тогда стоит переходить на Python.
Заключение
Bash – отличный инструмент для администрирования Linux-сервера, позволяющий автоматизировать резервное копирование, мониторинг и развертывание, а вместе с этим избавиться от рутины.
Если возникнут вопросы, напишите нам, пожалуйста, тикет из панели управления аккаунта (раздел “Помощь и поддержка”), а если вы захотите обсудить наши продукты с коллегами по цеху и сотрудниками Beget – ждем вас в нашем сообществе в Telegram.