Как запустить shell скрипт при ошибке доступа

«Ошибка «Permission denied» при запуске скрипта — это не просто техническая преграда, а сторожевой пес операционной системы, который заставляет задуматься: что именно ты пытаешься исполнить и с какими правами».

Что происходит при запуске скрипта

Ввод ./script.sh в терминале запускает цепочку событий, которую многие представляют слишком упрощенно. Ядро Linux проверяет не только наличие бита исполнения. Последовательность выглядит так:

  1. Проверка бита исполнения (x). Оболочка запрашивает у ядра выполнение файла. Ядро в первую очередь смотрит на права доступа файла для текущего пользователя. Если бит исполнения отсутствует — процесс останавливается с ошибкой Permission denied.
  2. Анализ содержимого файла. Если права есть, ядро читает первые несколько байт файла. Оно ищет сигнатуру #! (shebang).
  3. Создание нового процесса. Найденный интерпретатор (например, /bin/bash) запускается в отдельном процессе. Ему передается путь к скрипту как аргумент. Важно: скрипт сам по себе не является исполняемой программой — это текст, который читает интерпретатор.
  4. Исполнение. Интерпретатор построчно читает и выполняет команды из файла в новом процессе.

Сбой на любом из этих шагов приводит к разным ошибкам: от явного Permission denied до неочевидного bad interpreter, если путь в shebang неверен.

Терминал с запуском shell-скрипта

Пять способов запуска и их последствия

Способ запуска определяет не только необходимость в правах, но и контекст выполнения — это критично для безопасности и поведения скрипта.

Команда Требует бит +x Контекст выполнения Влияние на текущую оболочку
./script.sh Да Новый процесс. Запускается интерпретатор из shebang. Изменения переменных среды, рабочий каталог (cd), объявленные функции — всё остаётся внутри нового процесса и не влияет на родительскую оболочку.
bash script.sh Нет Новый процесс. Явно указан интерпретатор (bash), shebang игнорируется. Аналогично ./script.sh — изоляция в новом процессе.
source script.sh
или . script.sh
Нет Текущая оболочка. Команды скрипта выполняются так, как если бы вы ввели их вручную. Переменные, alias, функции, изменение каталога — всё это сохраняется после завершения скрипта. Это мощно, но опасно для непроверенного кода.
sh script.sh Нет Новый процесс в оболочке sh (обычно dash, а не bash). Изоляция. Может привести к синтаксическим ошибкам, если скрипт использует специфичные для bash конструкции ([[ ]], {1..10}).

Практический алгоритм диагностики

Когда сталкиваешься с отказом в запуске, системная диагностика экономит время. Вот проверенный порядок действий.

1. Проверка прав доступа

Выполни ls -l script.sh. В первой колонке ищи последовательность типа -rwxr-xr-x. Если для твоего пользователя (первые три символа после типа файла) отсутствует x, это причина ошибки.

Решение: chmod u+x script.sh — добавить право на исполнение только владельцу. Избегай chmod +x или, тем более, chmod 777, если скрипт используется в общей среде.

2. Проверка формата файла и shebang

Права есть, но скрипт не запускается? Проблема может быть в невидимых символах. Выполни head -1 script.sh | cat -A.

  • Если в конце строки видишь ^M — это возврат каретки из Windows (CRLF). Используй dos2unix script.sh или sed -i 's/r$//' script.sh.
  • Убедись, что shebang корректен: #!/bin/bash или #!/usr/bin/env bash. Второй вариант более переносим, так как ищет bash в переменной PATH.

3. Проверка доступности интерпретатора

Shebang указывает на /bin/bash, но в системе его нет по этому пути. Проверь: which bash или ls -l /bin/bash. Если пути различаются, исправь shebang или создай символьную ссылку.

4. Проверка синтаксиса

Интерпретатор может запуститься, но тут же завершиться с ошибкой из-за синтаксиса. Запусти проверку: bash -n script.sh. Ключ -n выполняет только синтаксический разбор без реального исполнения.

Опасные практики и безопасность

В корпоративной среде, особенно под требования 152-ФЗ и ФСТЭК, небрежность с правами доступа к скриптам создаёт уязвимости.

chmod 777 как антипаттерн

Команда chmod 777 script.sh даёт права на чтение, запись и исполнение всем пользователям системы, включая потенциально скомпрометированные учётные записи служб. Любой процесс с достаточными привилегиями может подменить содержимое скрипта на вредоносное. Минимально необходимый набор — 755 (владелец — всё, группа и другие — только чтение и исполнение). Для скриптов с чувствительными данными (пароли, ключи) лучше 700.

Запуск из непроверенных источников

Скачанный архив или вложение в письме — это зона риска. Перед запуском всегда проверяй содержимое: cat script.sh или less script.sh. Ищи подозрительные вызовы: curl | bash, rm -rf, chmod 777, запись в системные каталоги. Особенно опасно запускать такой код через source, так как он получит доступ ко всем переменным твоей сессии.

Скрипты от root и SUID-бит

Назначение бита SUID (chmod u+s script.sh) для скриптов в Linux обычно игнорируется из соображений безопасности. Если скрипт должен выполняться с привилегиями, используй sudo с явно прописанными правилами в /etc/sudoers, ограничивающими конкретные команды. Это обеспечивает подотчётность и принцип наименьших привилегий.

Когда использовать каждый метод запуска

Выбор метода — это выбор архитектуры выполнения.

./script.sh

Стандарт для готовых утилит и автоматизации. Предполагает, что скрипт самодостаточен, имеет корректный shebang и права. Все изменения изолированы. Используется в cron, systemd-сервисах, CI/CD-пайплайнах.

source script.sh или . script.sh

Применяется для загрузки настроек среды. Классические примеры: профиль оболочки (~/.bashrc), активация виртуального окружения Python, загрузка функций и alias. Помни, что exit в вызванном скрипте завершит всю текущую сессию терминала.

bash -x script.sh

Инструмент отладки. Ключ -x выводит каждую команду с её аргументами в стандартный поток ошибок (stderr) перед выполнением. Позволяет увидеть реальные значения переменных и логику ветвления. Для сложной отладки можно комбинировать с set -x внутри самого скрипта.

Запуск из другого скрипта или процесса

При вызове скрипта из другого скрипта или языка программирования (Python, Go) важно контролировать переменные среды и рабочий каталог. Используй абсолютные пути к скрипту. Передавай явные аргументы, а не полагайся на глобальное состояние. Учитывай коды возврата ($?) для обработки ошибок.

Понимание этих механизмов превращает ошибку «Permission denied» из раздражающего препятствия в осознанный сигнал о необходимости проверить контекст и безопасность планируемого действия.

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