Файлы, права и окружение — Примеры
Пример 1 — Скрипт, который не запускается
Развёртывание немедленно падает с Permission denied на скрипте, который прекрасно работает, если передать его интерпретатору. В листинге ниже — и сам файл, и его каталог: скажите, какого бита не хватает, приведите исправление и назовите изменение, которое вы делать не стали бы.
ls -l deploy.sh
# -rw-r--r-- 1 deploy deploy 218 deploy.sh
./deploy.sh
# bash: ./deploy.sh: Permission denied
ls -ld releases
# drw-rw-r-- 2 deploy deploy 4096 releases
cd releases
# bash: cd: releases: Permission denied
Решение
chmod +x deploy.sh # исполнение для владельца, группы и остальных
chmod +x releases # каталогу нужен бит исполнения, чтобы в него войти
# не это: chmod 777 deploy.sh
Права читаются слева направо, и у владельца здесь есть чтение и запись, а исполнения нет: поэтому голый ./deploy.sh и отвергается, тогда как bash deploy.sh работает, ведь интерпретатору достаточно прочитать файл. В каталоге тот же пробел, только в другом месте — без бита исполнения сквозь каталог ничего не пройдёт, и cd там падает. Тянуться ради обхода такой ошибки к правам на запись для всех — ловушка: тогда право переписать скрипт развёртывания получит каждая учётная запись на машине.
Пример 2 — Работает в терминале, падает в планировщике
Из интерактивной оболочки ночной скрипт запускается правильно, а под планировщиком падает с command not found. Ниже напечатаны оба окружения: скажите, какая переменная отличается и почему, а затем приведите исправление.
# интерактивная оболочка
echo "$PATH"
# /home/deploy/.local/bin:/usr/local/bin:/usr/bin:/bin
which backup-tool
# /home/deploy/.local/bin/backup-tool
# плановая задача
echo "$PATH"
# /usr/bin:/bin
backup-tool
# backup-tool: command not found
Решение
# назовите программу по полному пути внутри задачи
/home/deploy/.local/bin/backup-tool
# или задайте нужное задаче в начале скрипта
PATH="/usr/local/bin:/usr/bin:/bin:/home/deploy/.local/bin"
export PATH
Короткое имя команды оболочка ищет, обходя каталоги из PATH по порядку, а плановая задача стартует с минимальным окружением, а не с тем, которое построила ваша интерактивная оболочка, поэтому личного каталога в списке просто нет. Если назвать полный путь или задать путь там, где его прочитает сама задача, скрипт станет независимым от того, какая оболочка его запустила. Ловушка же — добавить запись в интерактивный файл конфигурации, который планировщик никогда не читает: тогда исправление будто работает при проверке вручную и снова падает следующей ночью.