После первого проекта скрипт теряет пути: ограничиваем cd подоболочкой

Скрипт последовательно заходит в несколько проектов и выполняет одинаковую проверку. Первый проект проходит, второй «не существует», хотя каталог на месте. Причина проста: cd изменил текущую папку всего скрипта. Следующий относительный путь теперь считается от первого проекта. Попытка вернуть всё через cd .. работает только при заранее известной глубине и ломается при раннем выходе.

Удобнее ограничить смену каталога одной операцией. Группа команд в круглых скобках выполняется в подоболочке. Она получает исходный рабочий каталог, может менять его внутри, а после завершения родитель продолжает из прежнего места. Так каждая итерация начинает с одинаковой точки отсчёта.

Два проекта и один отсутствующий каталог

Пример создаёт только учебные папки. Проверка читает marker.txt и не запускает сборку. Каталог missing нужен, чтобы убедиться: ошибка cd не приводит к выполнению команды в чужом проекте.

mkdir -p 'project one' 'project two'
printf '%s\n' one > 'project one/marker.txt'
printf '%s\n' two > 'project two/marker.txt'
failed=0
for project in 'project one' missing 'project two'; do
    if (
        cd -- "$project" || exit 2
        printf 'project=%s; value=' "$project"
        cat marker.txt
    ); then
        :
    else
        printf 'Проверка не выполнена: %s\n' "$project" >&2
        failed=1
    fi
done
printf 'Итог: %s\n' "$failed"

В stdout будут значения one и two, а для missing появится диагностика. Второй существующий проект найдётся даже после отказа посередине. Текущая папка родителя не меняется: каждый cd ограничен своей группой.

Проверка cd ... || exit 2 обязательна. Без неё после ошибки перехода cat прочитает marker.txt из исходного каталога, если такой файл там случайно есть. Это опаснее заметного падения: результат будет выглядеть успешным, но относиться к другой папке.

Изменения переменных тоже остаются внутри

Подоболочка изолирует не только cwd, но и присваивания shell-переменных. Если увеличить failed внутри круглых скобок, родитель этого не увидит. Поэтому общий статус меняется во внешней ветке else, которая получает результат всей группы. Это сохраняет связь между неудачным проектом и итогом batch.

В реальном исполняемом скрипте после цикла используйте exit с общим статусом. В учебном фрагменте итог печатается, чтобы его было удобно просмотреть в терминале. При переносе в CI не оставляйте одну успешную printf последней командой, если от результата проверок зависит весь job.

Если обработка включает несколько критичных команд, проверяйте их статусы явно либо связывайте так, чтобы отказ не терялся за последующим успешным выводом. Само наличие подоболочки решает область действия каталога, но не политику ошибок. Особенно внимательно читайте группы, используемые как условие if: поведение set -e в таком контексте не заменяет явных проверок.

Откуда брать пути

В примере все пути относительны папке запуска. Для рабочего batch часто удобнее один раз определить корневой каталог и строить пути от него. Если корень приходит параметром, проверьте его существование до обхода. Не рассчитывайте, что планировщик стартует из той же папки, где вы вручную проверяли скрипт.

Пробелы в именах сохраняются благодаря кавычкам при передаче project. Для произвольного списка каталогов нужен формат передачи, сохраняющий границы имён; разбор вывода ls через пробелы для этого не подходит. Начните с явного массива или аргументов скрипта и только затем добавляйте автоматический поиск проектов.

В программе Linux и Bash корректные пути, quoting и проверка ошибок входят в практику автоматизации. Откройте программу и продолжите к скриптам, которые одинаково обрабатывают несколько входов и не зависят от случайного состояния предыдущей операции.

Ещё по теме

Продолжить на практике

  • Linux и Bash для DevOps-инженеров ↗

    Linux для работы с серверами: процессы, права, systemd, сеть, диски и логи. Автоматизируйте повседневные задачи на Bash и разберите типичные сбои сервиса — от занятого порта до переполненного диска.