**Версия:** p11: glib2 2.84.4-alt1 (libgio 2.84.4-alt1), bash5 5.2.37-alt1 Исходники: https://ftp.altlinux.org/pub/distributions/ALTLinux/p11/branch/x86_64/SRPMS.classic/glib2-2.84.4-alt1.src.rpm Sisyphus: glib2 2.90.1-alt1 (libgio 2.90.1-alt1), bash5 5.2.37-alt2 ## Суть При выполнении TAB-дополнения расположения в командах `gio` (move, copy, cat, list и т. д.) в том случае, если дописываемое слово содержит кавычку (`"` или `'`), в терминал выводится ошибка синтаксиса bash, варианты завершения не показываются, а введённая пользователем строка теряется (оболочка возвращается к пустому промпту, команду приходится вводить заново). Сообщение в терминале (bash 5.2): bash: неожиданный конец файла во время поиска «"» (для одиночной кавычки: `во время поиска «'»`; в bash 4.4, например ветки p10, при том же сбое выводится дополнительная строка: `bash: синтаксическая ошибка: неожиданный конец файла`). Обнаружено при вводе FTP-URI в кавычках: $ gio move "ftp://<SERVER_IP>:7777/home/test/rn<TAB> bash: неожиданный конец файла во время поиска «"» bash: синтаксическая ошибка: неожиданный конец файла Однако ситуация воспроизводится с произвольным словом в кавычках, без FTP-сервера, без монтирований и без бэкендов gvfs: сбой происходит внутри функции завершения, до каких-либо обращений `gio list`. ## Воспроизведение 1. Интерактивный терминал (bash с загруженным bash-completion, например терминал в сессии рабочего стола). 2. Ввести команду без нажатия Enter (сервер из примера не обязан существовать, монтирование не требуется): $ gio move "ftp://<SERVER_IP>:7777/home/test/rn 3. Нажать TAB. Более простой вариант без URI: $ gio move "/home/test/ + TAB — тот же результат. ## Фактический результат 1. В терминал выводится ошибка bash: `неожиданный конец файла во время поиска «"»` (для `'` — `«'»`; в bash 4.4 плюс `синтаксическая ошибка: неожиданный конец файла`). 2. Варианты завершения не показываются. 3. Введённая пользователем строка очищается: последующий ввод и Enter исполняются как самостоятельная команда (проверено: после ошибки введённый один символ исполняется как отдельная команда, т. е. буфер строки пуст). Тот же результат и при кавычке, закрытой в конце слова (`gio move "ftp://.../rn"` + TAB) — по той же причине, см. «Где». ## Ожидаемый результат Варианты завершения из указанного расположения (список имён) либо, при отсутствии подходящих имён, отсутствие видимой реакции; введённая строка сохраняется, ошибки в терминал не выводится. ## Где `/usr/share/bash-completion/completions/gio` — сценарий bash-завершения утилиты `gio`, поставляется подпакетом `libgio` исходного пакета `glib2` (файл `glib/gio/completion/gio` в дереве исходников). Строки 67–69 (нумерация по 2.84.4): # Workaround to unescape dir name (e.g. "\ " -> " ") local -a tmp="( ${dir} )" local unescaped_dir="${tmp[0]}" Этот «workaround» разымыливает имя каталога (например, `\ ` -> ` `), опираясь на давнее поведение встроенных команд bash `local`/`declare`/`typeset`: значение, присваиваемое переменной-массиву, оболочка повторно разбирает как составное присваивание `NAME=(...)` со снятием кавычек (синтаксис составного присваивания описан в справочнике bash, раздел «Arrays»). Для «чистого» `dir` (без кавычек в значении) трюк работает: `local -a tmp="( /home/test/my\ dir )"` даёт `tmp[0]` = `my dir` с обычным пробелом. Однако `dir` строится из дописываемого слова (строки 44–54 сценария) и сохраняет введённые пользователем кавычки: при кавычке, закрытой в конце слова, она отрезается вместе с basename, при недописанном слове кавычка и так не закрыта. В обоих случаях значение, попадающее на повторный разбор, содержит неспаренную кавычку, например: ( "ftp://<SERVER_IP>:7777/home/test/ ) Далее: 1. bash выводит ошибку `неожиданный конец файла во время поиска «"»` (при выполнении вне интерактивной оболочки сообщение имеет префикс с именем файла и контекстом, например `/usr/share/bash-completion/completions/gio: array assign: строка 1:`); 2. текущая команда прерывается — функция `__gio_location` завершается сразу после этой строки, последующие строки не исполняются; 3. `COMPREPLY` остаётся пустым, поэтому варианты не показываются; 4. в интерактивной оболочке введённая пользователем строка теряется. Другие сценарии завершения GLib, поставляемые тем же пакетом (`gapplication`, `gdbus`, `gresource`, `gsettings`), такой конструкции не содержат. ## Доказательства (проверено на p11, bash 5.2.37-alt1) - Интерактивно (pty, `bash -i` с загруженным bash-completion): по описанному сценарию на первый TAB выводится приведённая ошибка; одинаково для `"` и `'`, для слова, оканчивающегося `/`, и для слова с закрытой кавычкой. Буфер введённой строки после этого пуст. - Контроль без кавычек в слове (`gio move /h` + TAB): дополнение работает (строка дополнена до `/home/`), ошибки нет, строка сохранена. - Та же конструкция вне механизма завершения: $ bash -c 'declare -a t="( \"x )"; echo ok' bash: array assign: строка 1: неожиданный конец файла во время поиска «"» (`ok` не выводится, rc=1) — подтверждено, что прерывается именно повторный разбор значения присваивания массива, т. е. строка 68 сценария. - Повторные попытки завершения повторяют ошибку, `COMPREPLY` каждый раз пуст. - В bash 4.4.23 (p10) поведение то же, при том же сбое выводится обе строки сообщения (это объясняет вторую строку в первичном отчёте); в bash 5.2.37 — одна. Различие лишь в форме вывода ошибки, механизм один и тот же — давнее стабильное поведение встроенных команд bash, не регрессия bash. ## Апстрим Сценарий — апстримный код (Copyright 2018 Red Hat, https://gitlab.gnome.org/GNOME/glib). Строка «Workaround to unescape dir name» присутствует в сценарии с момента его появления (glib 2.58.0, 2018; первоначально `declare -a`, затем `local -a` — конструкция та же) и сохранена без изменений в актуальном источнике 2.90.1. Апстримные улучшения bash-завершения утилит GLib в 2.81.0 (!3989, !4012, !4013) эту строку не затрагивали; в дереве packages/srpms/g/glib2.git файл идентичен во ветках p11 и sisyphus, ALT-патчи его не меняли. ## Затронутость - p11 glib2 2.84.4-alt1: **затронут** (воспроизведено на тестовой системе, bash5 5.2.37-alt1) - Sisyphus glib2 2.90.1-alt1: **затронут** (уровень исходников: `glib/gio/completion/gio` идентичен p11, строки 67–69 на месте) Баг предсуществующий (сценарий от 2018 года), не является регрессией ни какого-либо релиза glib2, ни bash, ни gvfs: сбой происходит до обращения к `gio list` и воспроизводится без монтирований, серверов и бэкендов gvfs. ## Проверка затронутости Без терминала достаточно убедиться, что установленный `/usr/share/bash-completion/completions/gio` содержит строку local -a tmp="( ${dir} )" и что повторный разбор bash срабатывает: bash -c 'declare -a t="( \"x )"; echo ok' # bash: array assign: строка 1: неожиданный конец файла во время поиска «"» # (ok не выводится) ## Просьба Исправить сценарий завершения `gio` в исходном пакете glib2 так, чтобы дописываемое слово, способное содержать неспаренные кавычки, не попадало на повторный разбор. Например, применять описанный трюк только при отсутствии кавычек в `dir`, а в остальных случаях ограничиться безопасным преобразованием: if [[ $dir == *[\'\"]* ]]; then unescaped_dir=${dir//\\ / } else local -a tmp="( ${dir} )" unescaped_dir="${tmp[0]}" fi (точная формулировка — на усмотрение мейнтейнера). При возможности — передать исправление в апстрим (https://gitlab.gnome.org/GNOME/glib).