md5sum добавляет '\' к контрольной сумме

22

Почему md5sum предшествует "\" перед контрольной суммой, когда находит контрольную сумму файла с "\" в имени?

$ md5sum /tmp/test\\test
\d41d8cd98f00b204e9800998ecf8427e  /tmp/test\\test

То же самое отмечено для любой другой утилиты.

jsaji
источник
Просто для справки, другие *sumутилиты (того же семейства, что md5sumи e, g и sha1sumт. Д.) В GNU coreutils делают то же самое.
Кусалананда
Я не вижу такого поведения, какая версия утилиты:md5sum --version
Kiwy
@Kusalananda Это может быть определенная версия coreutils; на CentOS 7 cksumнет; например% cksum test\\test 3915528286 4 test\test
Стивен Харрис
@StephenHarris Это, вероятно , потому, что cksumэто утилита POSIX и ее спецификация. не позволяет этого.
Кусалананда

Ответы:

33

Это задокументировано для Coreutils md5sum:

Если файл содержит обратную косую черту или символ новой строки, строка начинается с обратной косой черты, и каждый проблемный символ в имени файла экранируется обратной косой чертой, что делает вывод однозначным даже при наличии произвольных имен файлов.

( файл - это имя файла, а не его содержимое).

b2sum, sha1sumи различные инструменты SHA-2 ведут себя так же, как md5sum. sumи cksumнет; sumпредоставляется только для обратной совместимости (и его предки не производят цитируемый выход), и cksumэто определяется POSIX и не позволяет этого выхода.

Это поведение было введено в ноябре 2015 года и выпущено в версии 8.25 (январь 2016 года) со следующей NEWSзаписью:

md5sumтеперь обеспечивает единственную строку для каждого файла для статуса на стандартном выводе, используя '\' в начале строки и заменяя любые символы новой строки на '\ n'. Это также влияет sha1sum, sha224sum, sha256sum, sha384sumи sha512sum.

Обратная косая черта в начале строки служит в качестве флага: экранирование в именах файлов обрабатывается только в том случае, если строка начинается с обратной косой черты. (Unescaping не может быть поведением по умолчанию: он разрушит суммы, сгенерированные с более старыми версиями Coreutils, содержащими \\или \nсохраненными в именах файлов.)

Стивен Китт
источник
30
Обидно, что-то совершенно не интуитивное, как это не описано на manстраницах. (И да, я знаю, что GNU хочет, чтобы все читали их чрезвычайно запутанные infoстраницы.)
roaima
3
@msouth обратная косая черта в начале строки служит флагом, указывающим, что обратная косая черта в имени файла является экранированием; в противном случае вы не знаете, обрабатывать ли и \nт.д. как литералы или экранированные символы.
Стивен Китт
3
@msouth, если оно в начале имени файла, у вас нет возможности узнать, флаг это или имя файла, начинающееся с обратной косой черты ...
Стивен Китт,
1
@ StefhenKitt Я не думаю, что ведущий \ здесь для устранения неоднозначности. Нет никакой двусмысленности, если выходные данные задокументированы как всегда экранирующие косые черты и переводы строки. Это так, что не нужно делать де-побег, если не нужно. Вы, конечно, можете спорить, стоит ли это того (лично я думаю, что это не так, но я не coreutilsпомогаю).
TypeIA
1
Фраза документации "каждый проблемный символ в имени файла экранирован с обратной косой чертой" неверна; замена новой строки на \nэто не то же самое, что экранирование новой строки с обратной косой чертой!
Руах
17

Ответ Стивена Китта охватывает вопрос « что?», И я постараюсь объяснить, почему это изменение было реализовано. Во-первых, кто-то заметил, что имя файла, содержащее перевод строки 1, может привести к неоднозначному выводу . Например, рассмотрим этот вывод:

d41d8cd98f00b204e9800998ecf8427e  foo
25af89c92254a806b2e93fffd8ac1814  bar

Означает ли это, что было два файла fooи / barили только один файл с именем файла "foo\n25af89c92254a806b2e93fffd8ac1814 bar"? Конечно, эта последняя возможность крайне маловероятна, но она возможна. Чтобы устранить неоднозначность, разработчики решили экранировать символы новой строки с помощью обратной косой черты ( \). Выходной сигнал становится различимым. Однако тогда возникает еще одна двусмысленность:

764efa883dda1e11db47671c4a3bbd9e  foo\nbar

Содержит ли имя этого файла символ новой строки или обратную косую черту с последующим n? Чтобы решить эту проблему, нам также необходимо избежать обратной косой черты, чтобы последний случай стал:

764efa883dda1e11db47671c4a3bbd9e  foo\\nbar

Наконец, они решили добавить каждую выходную строку, содержащую такие экранированные символы, \\чтобы облегчить парсеру обнаружение выполнения экранирования. Предположительно это было сделано для того, чтобы парсеры могли обрабатывать выходные данные как из экранированных версий, так md5sumи из не экранированных версий (не-GNU). Этот флаг также означает, что «дорогостоящее» удаление не нужно делать, когда в этом нет необходимости. Вы можете увидеть пример этого анализа в действии md5sum.cсам по себе (строка 382 в связанной версии).


1 Под символом новой строки я подразумеваю символ, \nкоторый иногда также конкретно называют переводом строки или LF ; см md5sum.c.

TypeIA
источник
1
Конечно, вменяемым поведением будет полный запрет каждого файла, содержащего перевод строки. Просто отказывайтесь их обрабатывать.
труба
1
@pipe это безумное поведение. POSIX допускает такие имена файлов, а утилиты, намеренно отказывающиеся работать с легитимными файлами, являются плохими и должны быть убиты огнем.
Руслан
2
@Ruslan Смысл в том, чтобы протестовать против POSIX за то, что он допускает такие антисоциальные имена. Разрешение таких символов, вероятно, вызвало большое количество проблем безопасности и раздувания кода только для обработки таких особых случаев.
труба
@pipe, в то время как LF в имени файла действительно антисоциальны, другие вещи, упомянутые в вашей ссылке, гораздо более спорны - например, пробелы, нелатинские буквы и т. д.
Руслан
Классический сверхинжиниринг от инженеров. Урок (еще раз): не позволяйте инженерам управлять требованиями. Они найдут самый непонятный и запутанный случай, превратят его в основной случай и запутают всех.