Bash-скрипт — это когда вы однажды устали делать одно и то же вручную и решили что машина справится сама. Резервные копии, перезапуск сервисов, деплой, мониторинг, управление GPIO на Raspberry Pi — всё это автоматизируется парой десятков строк в текстовом файле. Звучит просто, но у начинающих всегда находится способ споткнуться: Permission denied, command not found, скрипт не запускается по крону хотя вручную работает отлично.
В этом руководстве разберём всё по порядку: как написать и запустить bash скрипт в Linux, как запускать скрипты через cron, как вызывать bash из Python, как работать с bash в Windows и как управлять GPIO на Raspberry Pi через shell-скрипты. Максимум практики, минимум воды.
Что такое bash скрипт и как он устроен
Bash скрипт — текстовый файл с последовательностью команд Linux/Unix, которые интерпретатор bash выполняет одну за другой. Никакой компиляции, никаких бинарников — просто файл с командами, которые вы и так могли бы набрать в терминале вручную.
Минимальный рабочий скрипт:
#!/bin/bash echo "Hello Linux" date
Первая строка — shebang (#!). Это не комментарий, это указание операционной системе каким интерпретатором выполнять файл. /bin/bash — путь к bash. Без shebang система не знает как запускать файл и либо откроет его в текстовом редакторе, либо выдаст ошибку.
Альтернативный вариант shebang, более переносимый между разными системами:
#!/usr/bin/env bash
Этот вариант находит bash через переменную PATH, что полезно когда bash может находиться в разных местах на разных системах (актуально для macOS, FreeBSD, некоторых Linux-дистрибутивов).
Структура типичного bash скрипта
#!/bin/bash
# Это комментарий — bash его игнорирует
# Переменные
NAME="Linux"
DATE=$(date +%Y-%m-%d)
# Вывод
echo "Привет, $NAME!"
echo "Сегодня: $DATE"
# Условие
if [ -f /etc/hosts ]; then
echo "Файл /etc/hosts существует"
else
echo "Файл не найден"
fi
# Цикл
for i in 1 2 3; do
echo "Итерация $i"
done
Сохраните это в файл script.sh — и переходим к запуску.
Запуск bash скрипта в Linux: три способа
Прежде чем запускать — скрипту нужно дать права на выполнение. Это делается один раз:
chmod +x script.sh
Команда chmod +x добавляет флаг исполняемости файлу. Без него Linux отказывается запускать файл как программу — даже если внутри правильный bash-код.
Способ 1: Прямой запуск
./script.sh
Точка и слеш перед именем файла означают «запустить файл из текущей директории». Без ./ bash будет искать script.sh в системных директориях из PATH и не найдёт его.
Способ 2: Через интерпретатор bash
bash script.sh
В этом случае права на выполнение не нужны — вы явно вызываете bash и передаёте ему файл как аргумент. Удобно для отладки и для запуска чужих скриптов без chmod.
Способ 3: Через полный путь
/home/user/scripts/script.sh
Нужен когда скрипт запускается не из его директории — например, из cron или systemd. Всегда используйте полные пути в автоматизации.
Проверка прав перед запуском
# Посмотреть права файла ls -la script.sh # -rwxr-xr-x 1 user user 45 Mar 12 10:00 script.sh # Символ x (execute) должен присутствовать # Дать права только владельцу chmod u+x script.sh # Дать права всем chmod +x script.sh # Или числовой вариант chmod 755 script.sh
Bash скрипт для запуска программ и сервисов
Одно из самых популярных применений bash — запуск нескольких программ одной командой. Скрипт последовательно или параллельно запускает всё что нужно.
Запуск одного приложения
#!/bin/bash # Открыть браузер firefox https://google.com # Запустить Python приложение python3 /home/user/app/main.py # Запустить Java приложение java -jar /opt/myapp/app.jar
Запуск нескольких сервисов
#!/bin/bash echo "=== Запуск сервисов ===" echo "Время: $(date)" # Запускаем nginx systemctl start nginx echo "nginx: запущен" # Запускаем <a class="wpil_keyword_link" href="https://it-apteka.com/tag/docker/" target="_blank" rel="noopener" title="Docker" data-wpil-keyword-link="linked" data-wpil-monitor-id="786">Docker</a> контейнер docker start my_container echo "Docker контейнер: запущен" # Запускаем Python воркер cd /home/user/app python3 worker.py & echo "Python воркер: запущен (PID: $!)" echo "=== Все сервисы запущены ==="
Символ & в конце команды запускает процесс в фоне. $! содержит PID последнего запущенного фонового процесса — полезно для логирования.
Скрипт с проверкой успешности запуска
#!/bin/bash
start_service() {
local service=$1
systemctl start $service
if systemctl is-active --quiet $service; then
echo "✓ $service запущен успешно"
else
echo "✗ Ошибка запуска $service"
exit 1
fi
}
start_service nginx
start_service postgresql
start_service redis
Запуск bash скрипта через cron
Cron — встроенный планировщик задач Linux. С его помощью скрипты запускаются автоматически по расписанию: каждую минуту, раз в час, раз в день, по будням в 3 ночи — как угодно.
Синтаксис cron
# Формат записи cron: # минуты часы день_месяца месяц день_недели команда # * * * * * /path/to/script.sh # Примеры: # 0 * * * * — каждый час (в 0 минут) # */5 * * * * — каждые 5 минут # 0 3 * * * — каждый день в 03:00 # 0 3 * * 1 — каждый понедельник в 03:00 # 0 3 1 * * — 1-го числа каждого месяца в 03:00 # 30 8 * * 1-5 — по будням в 8:30
Открыть редактор cron
crontab -e
Первый раз cron спросит какой редактор использовать — выбирайте nano если не знакомы с vim.
Практические примеры cron задач
# Бэкап базы данных каждую ночь в 3:00 0 3 * * * /home/user/scripts/backup_db.sh # Очистка логов каждое воскресенье в 4:00 0 4 * * 0 /home/user/scripts/clean_logs.sh # Мониторинг дискового пространства каждые 10 минут */10 * * * * /home/user/scripts/check_disk.sh # Перезапуск сервиса каждый день в 6:00 0 6 * * * systemctl restart myapp # Проверить список задач crontab -l # Удалить все задачи (осторожно!) crontab -r
Почему скрипт не работает в cron хотя вручную работает
Классическая проблема: скрипт отлично запускается в терминале, но молчит в cron. Причина — у cron другое окружение: нет переменных PATH, HOME, USER которые есть в интерактивной сессии.
#!/bin/bash # ВСЕГДА указывайте полные пути в cron-скриптах # Не: python3 script.py # А: /usr/bin/python3 /home/user/scripts/script.py # Задайте PATH в начале скрипта PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin # Или добавьте PATH в начало crontab # PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin # Перенаправляйте вывод в лог для отладки 0 3 * * * /home/user/scripts/backup.sh >> /var/log/backup.log 2>&1
Конструкция >> /var/log/backup.log 2>&1 записывает и обычный вывод, и ошибки в лог-файл. Незаменимо при отладке cron-задач.
Альтернатива cron: systemd timers
# Создать timer unit (более современный способ) # /etc/systemd/system/backup.timer [Unit] Description=Daily <a class="wpil_keyword_link" href="https://it-apteka.com/category/rezervnoe-kopirovanie/" target="_blank" rel="noopener" title="Резервное копирование" data-wpil-keyword-link="linked" data-wpil-monitor-id="790">Backup</a> Timer [Timer] OnCalendar=daily Persistent=true [Install] WantedBy=timers.target # Включить и запустить sudo systemctl enable backup.timer sudo systemctl start backup.timer # Посмотреть все timers systemctl list-timers
Запуск bash скрипта из Python
Python и bash отлично работают в паре. Python берёт на себя логику, обработку данных и API-взаимодействие, bash — системные операции, управление файлами и вызов утилит. Запустить bash из Python можно несколькими способами.
subprocess.run — рекомендуемый способ
import subprocess
# Простой запуск скрипта
result = subprocess.run(["bash", "script.sh"])
# Запуск с перехватом вывода
result = subprocess.run(
["bash", "script.sh"],
capture_output=True,
text=True
)
print("Вывод:", result.stdout)
print("Ошибки:", result.stderr)
print("Код возврата:", result.returncode)
# Запуск shell-команды строкой
result = subprocess.run(
"ls -la /home/user",
shell=True,
capture_output=True,
text=True
)
print(result.stdout)
subprocess.Popen — для долгих процессов
import subprocess
# Запуск в фоне с чтением вывода в реальном времени
process = subprocess.Popen(
["bash", "long_script.sh"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
# Читаем вывод по мере поступления
for line in process.stdout:
print(line, end="")
# Ждём завершения
process.wait()
print(f"Скрипт завершён с кодом: {process.returncode}")
os.system — простой но ограниченный способ
import os # Простой запуск — возвращает только код возврата exit_code = os.system("bash script.sh") # Получить вывод через os.popen (устаревший способ) output = os.popen("bash script.sh").read() print(output)
os.system проще, но не даёт перехватить вывод напрямую. Для новых проектов используйте subprocess — он гибче и безопаснее.
Практический пример: Python запускает bash и обрабатывает результат
import subprocess
def run_script(script_path, *args):
"""Запустить bash скрипт и вернуть результат"""
cmd = ["bash", script_path] + list(args)
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=30 # таймаут 30 секунд
)
if result.returncode != 0:
raise RuntimeError(f"Скрипт завершился с ошибкой:\n{result.stderr}")
return result.stdout.strip()
# Использование
try:
output = run_script("/home/user/scripts/backup.sh", "--database", "mydb")
print(f"Бэкап успешен: {output}")
except RuntimeError as e:
print(f"Ошибка: {e}")
except subprocess.TimeoutExpired:
print("Скрипт выполнялся слишком долго")
Запуск bash скриптов на Raspberry Pi
Raspberry Pi работает под управлением Linux (Raspberry Pi OS — это Debian), поэтому всё вышесказанное применимо напрямую. Но у RPi есть своя специфика — управление GPIO через bash-скрипты.
Управление GPIO через bash
#!/bin/bash # Установка утилиты gpio (если не установлена) # sudo apt install wiringpi # Включить пин GPIO 17 как выход и установить HIGH gpio -g mode 17 out gpio -g write 17 1 echo "GPIO 17: включён" sleep 2 # Установить LOW gpio -g write 17 0 echo "GPIO 17: выключен"
Мигание светодиода — классический Hello World для GPIO
#!/bin/bash
PIN=17
# Настройка пина
gpio -g mode $PIN out
echo "Мигание светодиода на пине $PIN. Ctrl+C для остановки."
# Бесконечный цикл мигания
while true; do
gpio -g write $PIN 1
sleep 0.5
gpio -g write $PIN 0
sleep 0.5
done
Автозапуск скрипта на Raspberry Pi
Три основных способа автоматически запускать скрипт при загрузке RPi:
# Способ 1: cron с @reboot crontab -e # Добавить: @reboot /home/pi/scripts/gpio_init.sh # Способ 2: systemd service # Создать файл /etc/systemd/system/gpio-init.service: [Unit] Description=GPIO Initialization After=multi-user.target [Service] Type=oneshot ExecStart=/home/pi/scripts/gpio_init.sh User=pi [Install] WantedBy=multi-user.target # Включить: sudo systemctl enable gpio-init.service # Способ 3: /etc/rc.local (старый способ, всё ещё работает) sudo nano /etc/rc.local # Добавить перед строкой "exit 0": /home/pi/scripts/gpio_init.sh &
Скрипт мониторинга температуры RPi
#!/bin/bash
# Получить температуру процессора
TEMP=$(vcgencmd measure_temp | grep -oP '\d+\.\d+')
echo "Температура CPU: ${TEMP}°C"
# Предупреждение при перегреве
THRESHOLD=70
if (( $(echo "$TEMP > $THRESHOLD" | bc -l) )); then
echo "ВНИМАНИЕ: Перегрев! $TEMP°C > $THRESHOLD°C"
# Отправить уведомление, включить вентилятор и т.д.
fi
Запуск bash скриптов в Windows
Windows — не Linux, но запускать bash-скрипты там вполне реально. Несколько способов на выбор в зависимости от задачи.
WSL (Windows Subsystem for Linux) — полноценный Linux в Windows
# Установка WSL (PowerShell от администратора) wsl --install # После перезагрузки — выбрать дистрибутив (по умолчанию Ubuntu) # Запустить Linux окружение: wsl # Внутри WSL — обычный bash bash script.sh ./script.sh # <a href="https://it-apteka.com/powershell-skripty-v-windows-kak-sozdat-zapustit-i-avtomatizirovat-vypolnenie/" target="_blank" rel="noopener" data-wpil-monitor-id="799">Запустить bash скрипт из PowerShell</a> через WSL wsl bash /home/user/script.sh # Запустить скрипт Windows-пути через WSL wsl bash "//c/Users/User/scripts/script.sh"
WSL — лучший способ если вам нужна полная совместимость с Linux-скриптами. Полноценное ядро Linux, apt, все системные утилиты.
Git Bash — простое решение для разработчиков
# Установить <a class="wpil_keyword_link" href="https://it-apteka.com/tag/git/" target="_blank" rel="noopener" title="Git" data-wpil-keyword-link="linked" data-wpil-monitor-id="788">Git</a> for Windows — в комплекте идёт Git Bash # https://git-scm.com/download/win # Запуск скрипта в Git Bash: ./script.sh bash script.sh # Запуск из командной строки Windows с Git Bash: "C:\Program Files\Git\bin\bash.exe" script.sh
Git Bash — хороший выбор для разработчиков, которые уже используют Git. Не требует включения WSL, работает из коробки.
PowerShell + WSL
# Запустить bash скрипт из PowerShell wsl bash script.sh # Запустить с аргументами wsl bash /path/to/script.sh arg1 arg2 # Получить вывод в переменную PowerShell $output = wsl bash /path/to/script.sh Write-Host $output [/bash> <h3>Cygwin — альтернатива WSL</h3> <p>Cygwin предоставляет POSIX-совместимую среду для Windows. Старше WSL, но иногда полезен для совместимости. Установите с <a href="https://www.cygwin.com" target="_blank" rel="noopener">cygwin.com</a> и запускайте скрипты так же как в Linux.</p> <h2>Типичные ошибки при запуске bash скриптов</h2> <h3>Permission denied</h3> [bash] # Ошибка: bash: ./script.sh: Permission denied # Решение: дать права на выполнение chmod +x script.sh # Или запустить явно через bash bash script.sh
Command not found
# Ошибка: ./script.sh: line 5: python3: command not found # Причина: команда не найдена в PATH (часто в cron) # Решение: использовать полный путь which python3 # узнать где находится python3 # /usr/bin/python3 # В скрипте писать полный путь: /usr/bin/python3 app.py # Или добавить PATH в начало скрипта: PATH=/usr/local/bin:/usr/bin:/bin
Неправильный shebang или конец строки Windows
# Ошибка: /bin/bash^M: bad interpreter # Причина: файл создан в Windows (CRLF окончания строк) # Решение: конвертировать в Unix формат (LF) dos2unix script.sh # Или через sed: sed -i 's/\r//' script.sh # Или через vim: # :set ff=unix # :wq
Скрипт не находит файлы с относительными путями
#!/bin/bash
# Проблема: скрипт ищет файлы относительно текущей директории,
# а не директории где лежит скрипт
# Решение: всегда переходить в директорию скрипта
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# Теперь относительные пути работают корректно
cat config.txt
python3 helper.py
Скрипт не завершается при ошибке
#!/bin/bash # По умолчанию bash продолжает выполнение даже при ошибках # Добавьте в начало скрипта: set -e # завершить при любой ошибке set -u # ошибка при использовании неопределённой переменной set -o pipefail # ошибка в pipeline = ошибка всей команды # Или кратко: set -euo pipefail # Теперь если любая команда вернёт ненулевой код — скрипт остановится
Шпаргалка по запуску bash скриптов
# ===== СОЗДАНИЕ И ЗАПУСК ===== # Создать скрипт nano script.sh # Дать права chmod +x script.sh # Запустить ./script.sh bash script.sh /полный/путь/к/script.sh # ===== CRON ===== # Редактировать расписание crontab -e # Посмотреть задачи crontab -l # Примеры расписания: */5 * * * * # каждые 5 минут 0 * * * * # каждый час 0 3 * * * # ежедневно в 3:00 0 3 * * 1 # каждый понедельник в 3:00 @reboot # при загрузке системы # Запуск с логированием в cron: 0 3 * * * /home/user/script.sh >> /var/log/script.log 2>&1 # ===== PYTHON ===== # Запустить скрипт import subprocess subprocess.run(["bash", "script.sh"]) # С перехватом вывода result = subprocess.run(["bash", "script.sh"], capture_output=True, text=True) print(result.stdout) # ===== WINDOWS ===== # WSL wsl bash script.sh # Git Bash bash script.sh # ===== RASPBERRY PI GPIO ===== gpio -g mode 17 out # пин как выход gpio -g write 17 1 # установить HIGH gpio -g write 17 0 # установить LOW gpio -g read 17 # прочитать состояние # ===== ОТЛАДКА ===== # Подробный вывод выполнения bash -x script.sh # Проверить синтаксис без выполнения bash -n script.sh # Безопасный режим в скрипте set -euo pipefail
Заключение
Bash-скрипты — один из фундаментальных навыков системного администратора и DevOps-инженера. Они позволяют автоматизировать рутину, запускать сложные последовательности команд одним вызовом, планировать задачи через cron и интегрировать системные операции с Python-приложениями.
Главные правила которые сэкономят вам время:
- Всегда используйте полные пути в скриптах для cron и systemd — PATH там другой
- Перенаправляйте вывод в лог (
>> script.log 2>&1) при автоматическом запуске — иначе ошибки уходят в никуда - Добавляйте
set -euo pipefailв начало скриптов — скрипт остановится при первой ошибке вместо того чтобы продолжать и ломать систему - Тестируйте с
bash -x— режим трассировки покажет каждую выполняемую команду
Есть вопросы по конкретному сценарию автоматизации или столкнулись с непонятной ошибкой? Пишите в комментарии — разберём.
Оставайтесь на связи
Рецепты от IT-боли. Без воды, без рекламы, без маркетинговой шелухи.
Подписаться на IT-Аптеку →



