Запуск bash скриптов в Linux: через терминал, cron, Python, Windows и Raspberry Pi

Как запустить bash скрипт в Linux: через терминал, cron, Python и Windows. Примеры команд, типичные ошибки и GPIO на Raspberry Pi — всё в одном руководстве

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 &quot;//c/Users/User/scripts/script.sh&quot;

WSL — лучший способ если вам нужна полная совместимость с Linux-скриптами. Полноценное ядро Linux, apt, все системные утилиты.

Git Bash — простое решение для разработчиков

# Установить &lt;a class=&quot;wpil_keyword_link&quot; href=&quot;https://it-apteka.com/tag/git/&quot; target=&quot;_blank&quot;  rel=&quot;noopener&quot; title=&quot;Git&quot; data-wpil-keyword-link=&quot;linked&quot;  data-wpil-monitor-id=&quot;788&quot;&gt;Git&lt;/a&gt; for Windows — в комплекте идёт Git Bash
# https://git-scm.com/download/win

# Запуск скрипта в Git Bash:
./script.sh
bash script.sh

# Запуск из командной строки Windows с Git Bash:
&quot;C:\Program Files\Git\bin\bash.exe&quot; 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&gt;

&lt;h3&gt;Cygwin — альтернатива WSL&lt;/h3&gt;

&lt;p&gt;Cygwin предоставляет POSIX-совместимую среду для Windows. Старше WSL, но иногда полезен для совместимости. Установите с &lt;a href=&quot;https://www.cygwin.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;cygwin.com&lt;/a&gt; и запускайте скрипты так же как в Linux.&lt;/p&gt;

&lt;h2&gt;Типичные ошибки при запуске bash скриптов&lt;/h2&gt;

&lt;h3&gt;Permission denied&lt;/h3&gt;

[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 &#039;s/\r//&#039; script.sh

# Или через vim:
# :set ff=unix
# :wq

Скрипт не находит файлы с относительными путями

#!/bin/bash

# Проблема: скрипт ищет файлы относительно текущей директории,
# а не директории где лежит скрипт

# Решение: всегда переходить в директорию скрипта
SCRIPT_DIR=&quot;$(cd &quot;$(dirname &quot;${BASH_SOURCE[0]}&quot;)&quot; &amp;&amp; pwd)&quot;
cd &quot;$SCRIPT_DIR&quot;

# Теперь относительные пути работают корректно
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 &gt;&gt; /var/log/script.log 2&gt;&amp;1

# ===== PYTHON =====

# Запустить скрипт
import subprocess
subprocess.run([&quot;bash&quot;, &quot;script.sh&quot;])

# С перехватом вывода
result = subprocess.run([&quot;bash&quot;, &quot;script.sh&quot;], 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-Аптеку →
Поделитесь:

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх