Короткий ответ
Относительный путь интерпретируется от текущей рабочей директории процесса, а она у cron (как правило, $HOME пользователя или /) и в терминале разработчика отличается; поэтому скрипт с относительными путями и урезанным PATH из cron часто не находит ни свои файлы, ни внешние команды, хотя при ручном запуске из нужной директории всё работает.
Как это работает подробнее
при ручном запуске из терминала рабочая директория — та, где вы находитесь, и PATH содержит все пути из профиля оболочки (.bashrc, .profile); cron запускает задачи с минимальным окружением, без загрузки профиля пользователя и обычно с рабочей директорией $HOME или неопределённой.
Пример кода
example-478.sh
# plohoy variant: сработает только если запустить руками из нужной папки
#!/usr/bin/env bash
source ./env_vars.sh
python3 report.py
# nadezhny variant: не зависит от текущей директории запуска
#!/usr/bin/env bash
cd "$(dirname "$0")"
source ./env_vars.sh
/usr/bin/python3 report.pyЧто использовать на практике
- Рекомендация. в скриптах автоматизации нужно либо использовать абсолютные пути ко всем файлам и исполняемым командам, либо явно переходить в нужную директорию в начале скрипта (
cd "$(dirname "$0")"или заданный абсолютный путь), а также явно задаватьPATHи нужные переменные окружения в самом скрипте или в crontab.
Подводные камни
- Ошибка. полагаться на относительные пути вида
./config.yamlили../scripts/helper.shбез явногоcd; рассчитывать, что переменные окружения вродеPATH,JAVA_HOMEили алиасы из.bashrcдоступны в cron так же, как в интерактивной сессии.