Skip to content

[bug] update.sh: repair-pass не запускается на macOS — апостроф в комментарии внутри <( ) ломает сканер bash 3.2, маркер .update-incomplete не снимается #433

Description

@faizulinda

Симптом

bash update.sh --yes на macOS доходит до repair-pass и падает:

update.sh: line 617: bad substitution: no closing `)' in <(
        # issue #402: path via argv, not interpolated — see FILES_MATCH above for why.
        # stderr is NOT suppressed here on purpose: the old `2>/dev/null` made a
        # broken interpreter (or, before this fix, an embedded path native Python
        # couldn't resolve) return zero rows with no diagnostic — "nothing to
        ...

Дальше скрипт не идёт: из-за set -e (строка 13) finish_update_transaction не вызывается, и маркер .update-incomplete не снимается. Повторный запуск ведёт себя ровно так же, то есть штатный совет «успешный повторный запуск снимет маркер» на macOS недостижим в принципе.

У нас маркер держится с 10.08 (state=applying, upstream_version=0.38.2), три запуска подряд не смогли его снять.

Причина

Не в самом коде — код синтаксически верен, bash -n update.sh проходит с кодом 0. Ломается сканер <( ... ) в bash 3.2: разбирая тело подстановки процессов, он не пропускает #-комментарии, поэтому апостроф внутри комментария читается как открывающая кавычка, и закрывающая ) не находится никогда.

Виновник — слово couldn't в комментарии внутри блока (строка ~697):

    done < <(
        # ...
        # broken interpreter (or, before this fix, an embedded path native Python
        # couldn't resolve) return zero rows with no diagnostic — "nothing to
        # ...
    )

Минимальное воспроизведение:

$ cat min.sh
#!/bin/bash
f() {
  while read -r x; do :; done < <(
    # couldn't resolve
    echo hi
  )
}
f
echo MINIMAL_OK

$ /bin/bash min.sh
min.sh: line 2: bad substitution: no closing `)' in <(
    # couldn't resolve
    echo hi
  )
MINIMAL_OK

Убрать апостроф (could not resolve) — тот же файл отрабатывает молча. На bash 5 обе версии работают.

macOS ставит bash 3.2 системным (GNU bash, version 3.2.57(1)-release, arm64-apple-darwin25), а шебанг скрипта — #!/bin/bash, то есть берётся именно он. На Linux с bash 5 дефект не виден — ни в CI, ни у автора.

Блок комментариев появился правкой по #402 (она чинила «тихий ноль строк» при сломанном интерпретаторе). Правка достигла своей цели и ценой этого сделала весь repair-pass недостижимым на macOS.

Последствия

  1. repair-pass не выполняется никогда на macOS — ровно та проверка, которая должна ловить недоставленные и протухшие runtime-файлы после частичного обновления.
  2. .update-incomplete не снимается, инсталляция навсегда числится в состоянии «обновление применено частично».
  3. Каскад: day-open-scaffold.sh и day-open-pipeline.sh из поставки не встают на место ([bug] Обновлённые day-open-scaffold.sh и day-open-pipeline.sh не запускаются из seed-расположения: scripts/lib/common.sh не сеется #427), утренний план четвёртые сутки собирает запасная ветка.

Пересекается с #423, #424, #426, #427, #428 — все про то, что 0.38.x не доезжает до инсталляции целиком.

Починка

Минимальная: убрать апострофы и прочие кавычки из комментариев внутри <( ... ) — например, couldn't resolvecould not resolve. Проверено: снимает ошибку.

Устойчивая: не держать комментарии внутри подстановки процессов вообще — вынести формирование списка файлов в отдельную функцию и вызывать её как done < <(list_manifest_files), а пояснения оставить над функцией. Тогда любая будущая правка комментария не сможет снова сломать разбор на bash 3.2.

Стоит заодно прогнать grepом остальные <( ... ) в поставке — конструкция многострочная с комментариями встречается не только здесь.

Проверка после починки

cd FMT-exocortex-template && bash update.sh --yes
ls .update-incomplete    # ожидается «No such file or directory»

Окружение

  • macOS (Darwin 25.5.0, arm64), /bin/bash 3.2.57
  • update.sh v2.4.1, upstream 0.38.3

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions