В файловой системе, где имена файлов находятся в UTF-8, у меня есть файл с ошибочным именем; оно отображается как:, D�sinstaller
фактическое имя в соответствии с zsh:, D$'\351'sinstaller
Latin1 для Désinstaller
, само по себе французское варварство для «удаления». Zsh не совпал бы с этим, [[ $file =~ '^.*$' ]]
но совпал бы с глобусом *
- это поведение, которое я ожидаю.
Теперь я все еще ожидаю найти его во время работы find . -name '*'
- на самом деле, я бы никогда не ожидал, что имя файла не пройдет этот тест. Тем не менее, с LANG=en_US.utf8
, файл не отображается, и я должен установить LANG=C
(или en_US
, или ''
) для его работы.
Вопрос: Что такое реализация и как я мог предсказать этот результат?
Информация: Arch Linux 3.14.37-1-lts, find (GNU findutils) 4.4.2
convmv
конвертировать имена файлов в UTF-8?[[ $file =~ '^.*$' ]]
не указыватьrecode
имя файла, но сейчас я посмотрю,convmv
если это будет необходимо. Спасибо.Ответы:
Это действительно хороший улов. Из быстрого взгляда на исходный код для поиска GNU я бы сказал, что это сводится к тому, как
fnmatch
ведет себя недопустимые последовательности байтов (pred_name_common
inpred.c
):Этот код проверяет возвращаемое значение
fnmatch
на равенство с 0, но не проверяет наличие ошибок; это приводит к тому, что о любых ошибках сообщают как "не совпадает".Много лет назад было предложено изменить поведение этой функции libc, чтобы она всегда возвращала истину в
*
шаблоне, даже для неработающих имен файлов, но из того, что я могу сказать, идея должна быть отклонена (см. Поток, начинающийся с https. : //sourceware.org/ml/libc-hacker/2002-11/msg00071.html ):Как упомянул Стефан Шазелас в комментарии, а также в том же потоке 2002 года, это не согласуется с расширением глобуса, выполняемым оболочками, которые не блокируют недопустимые символы. Возможно, еще более загадочным является тот факт, что при реверсе теста будут сопоставляться только те файлы, которые имеют сломанные имена (создайте файлы в bash с помощью
touch $'D\351marrer' $'Touch\303\251' $'\346\227\245\346\234\254\350\252\236'
):Итак, чтобы ответить на ваш вопрос, вы могли бы предсказать это, зная поведение вашего
fnmatch
в этом случае и зная, какfind
обрабатывает возвращаемое значение этой функции; Вы, вероятно, не могли бы узнать только прочитав документацию.источник
*
состоит в том, что тогда это будет несовместимо сD*staller
.D*staller
это соответствовало$'D\351sinstaller'
так же, как это происходит в глобусе всех оболочек, которые я тестировал. Учитывая, что поведение GNU fnmatch не соответствует поведению оболочки GNU, я бы сказал, что это ошибка..
должна соответствовать только действительным символам в кодировке - отсюда мое ожидание, которое.*
не соответствует недопустимым строкам - но я не могу найти подходящую спецификацию для всплывающей звезды.-name '*'
всеми файлами, включая сломанные имена), так что, по-видимому, версия BSDfnmatch
, которая не претендует на стандарт POSIX.2, в отличие от версии GNU, она имеет другую и, возможно, более разумную интерпретацию того, что следует делать с недопустимыми символами.-name
Опция find использует нотацию сопоставления с образцом оболочки для сопоставления имени файла.*
шаблон, соответствующий нескольким символам , должен соответствовать строке из нуля или более символов.find
использует fnmatch для проверки соответствия шаблону, поэтому вы можете использовать ltrace для проверки результата:С
D\351sinstaller
,fnmatch
возвращение-1
, указала , что она не соответствовала. Действительный символ какሒaa
будет сопоставлен.В вашем случае, с
UTF-8
локалью,\351
это недопустимый символ, приводящий к сбою сопоставления с шаблоном.источник
ltrace
. Я знал об этомstrace
, ноltrace
для меня это ново. Прекрасный!