md5sum poprzedza „\” sumą kontrolną

22

Dlaczego md5sum zastępuje „\” przed sumą kontrolną podczas znajdowania sumy kontrolnej pliku z „\” w nazwie?

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

To samo dotyczy każdego innego narzędzia.

jsaji
źródło
Dla porównania, inne *sumnarzędzia (z tej samej rodziny co md5sum, e, g sha1sumitp.) W jądrach GNU robią to samo.
Kusalananda
Nie widzę tego zachowania, jaka jest wersja narzędzia:md5sum --version
Kiwy
@Kusalananda Może to być specyficzna dla coreutils wersja; na CentOS 7 cksumnie; np.% cksum test\\test 3915528286 4 test\test
Stephen Harris
@StephenHarris To prawdopodobnie dlatego, że cksumjest narzędziem POSIX i jego specyfikacją. nie pozwala na to.
Kusalananda

Odpowiedzi:

33

Jest to udokumentowane dla Coreutils md5sum:

Jeśli plik zawiera odwrotny ukośnik lub nową linię, wiersz rozpoczyna się odwrotnym ukośnikiem, a każdy problematyczny znak w nazwie pliku jest poprzedzany odwrotnym ukośnikiem, dzięki czemu dane wyjściowe są jednoznaczne, nawet w obecności dowolnych nazw plików.

( plik to nazwa pliku, a nie jego zawartość).

b2sum, sha1suma różne narzędzia SHA-2 zachowują się w taki sam sposób jak md5sum. sumi cksumnie; sumjest zapewniony tylko dla kompatybilności wstecznej (a jego przodkowie nie wytwarzają danych wyjściowych cytowanych) i cksumjest określony przez POSIX i nie pozwala na ten typ danych wyjściowych.

To zachowanie zostało wprowadzone w listopadzie 2015 r. I wydane w wersji 8.25 (styczeń 2016 r.), Z następującym NEWSwpisem:

md5sumteraz zapewnia jeden wiersz dla pliku dla statusu na standardowym wyjściu, używając „\” na początku wiersza i zastępując wszelkie nowe wiersze „\ n”. To także wpływa na sha1sum, sha224sum, sha256sum, sha384sumi sha512sum.

Odwrotny ukośnik na początku linii służy jako flaga: znaki ucieczki w nazwach plików są przetwarzane tylko wtedy, gdy linia zaczyna się od odwrotnego ukośnika. (Unescaping nie może być zachowaniem domyślnym: spowodowałoby to uszkodzenie sum wygenerowanych przez starsze wersje Coreutils zawierające \\lub \nw przechowywanych nazwach plików).

Stephen Kitt
źródło
30
Szkoda, że ​​coś zupełnie nieintuicyjnego nie jest udokumentowane na manstronach. (I tak, wiem, że GNU chce, aby wszyscy infozamiast tego czytali bardzo skomplikowane strony).
roaima
3
@msouth odwrotny ukośnik na początku wiersza służy jako flaga wskazująca, że ​​odwrotne ukośniki w nazwie pliku są znakami ucieczki; w przeciwnym razie nie wiedziałbyś, czy przetworzyć \nitp. jako literały czy ucieczki.
Stephen Kitt
3
@msouth, jeśli jest na początku nazwy pliku, nie masz możliwości dowiedzieć się, czy jest to flaga, czy nazwa pliku naprawdę zaczyna się od odwrotnego ukośnika ...
Stephen Kitt
1
@StephenKitt Nie wydaje mi się, żeby wiodący \ był w stanie ujednoznacznić. Nie ma dwuznaczności, jeśli wynik jest udokumentowany jako zawsze unikający ukośników odwrotnych i znaków nowej linii. Ma to na celu zapobieganie ucieczce, jeśli nie jest konieczne. Możesz oczywiście zastanowić się, czy to jest tego warte (osobiście uważam, że nie jest, ale nie jestem coreutilsuczestnikiem).
TypeIA
1
Wyrażenie dokumentacji „każdy problematyczny znak w nazwie pliku jest poprzedzany ukośnikiem odwrotnym” jest niepoprawny; zastąpienie nowego wiersza znakiem \nnie jest tym samym, co ucieczka nowego wiersza odwrotnym ukośnikiem!
ruakh
17

Odpowiedź Stephena Kitta obejmuje to, co postaram się wyjaśnić, dlaczego wprowadzono tę zmianę. Po pierwsze, ktoś zauważył, że nazwa pliku zawierająca nowy wiersz 1 może powodować niejednoznaczne wyniki . Rozważmy na przykład:

d41d8cd98f00b204e9800998ecf8427e  foo
25af89c92254a806b2e93fffd8ac1814  bar

Czy to oznacza, że ​​były dwa pliki fooi barczy tylko jeden plik, którego nazwa pliku to "foo\n25af89c92254a806b2e93fffd8ac1814 bar"? To prawda, że ​​ta ostatnia możliwość jest wysoce nieprawdopodobna, ale jest możliwa. Aby rozwiązać niejednoznaczność, programiści postanowili uciec od nowego wiersza za pomocą odwrotnego ukośnika ( \). Dane wyjściowe stają się następnie rozróżnialne. Istnieje jednak dalsza dwuznaczność:

764efa883dda1e11db47671c4a3bbd9e  foo\nbar

Czy nazwa tego pliku zawiera znak nowej linii, czy odwrotny ukośnik, a po nim znak n? Aby rozwiązać ten problem, musimy również uciec z ukośników odwrotnych, aby ten drugi przypadek stał się:

764efa883dda1e11db47671c4a3bbd9e  foo\\nbar

Na koniec postanowili wstawić do każdego wiersza wyjściowego, który zawiera takie znaki ucieczki, \\aby ułatwić analizatorowi parserowi wykrycie, czy zostało to wykonane. Prawdopodobnie zostało to zrobione, aby umożliwić parserom obsługę danych wyjściowych zarówno z wersji uciekających, jak i z wersji md5sumnie-uciekających (innych niż GNU). Flaga oznacza również, że „kosztownego” ucieczki nie trzeba wykonywać, gdy nie jest to konieczne. Możesz zobaczyć przykład tego parsowania w akcji md5sum.csam w sobie (wiersz 382 w wersji połączonej).


1 Dzięki nowej linii mam na myśli postać \n, która jest czasami również specjalnie określany jako wysuw wiersza lub LF ; zob md5sum.c.

TypeIA
źródło
1
Oczywiście rozsądnym zachowaniem byłoby całkowite zablokowanie każdego pliku zawierającego nowy wiersz. Po prostu odmów ich przetwarzania.
rura
1
@pipe to szalone zachowanie. POSIX zezwala na takie nazwy plików, a narzędzia celowo odmawiające pracy z prawidłowymi plikami są złe i muszą zostać zabite ogniem.
Ruslan
2
@Ruslan Chodzi o to, aby zaprotestować przeciwko POSIX za dopuszczenie takich aspołecznych nazwisk. Zezwolenie na takie znaki prawdopodobnie spowodowało wiele problemów związanych z bezpieczeństwem i rozdęcie kodu tylko w celu obsługi takich specjalnych przypadków.
rura
@pipe, podczas gdy LF w nazwie pliku jest rzeczywiście antyspołeczny, inne rzeczy wymienione w twoim linku są o wiele bardziej dyskusyjne - jak spacje, litery niełacińskie itp.
Ruslan
Klasyczna nadprodukcja przez inżynierów. Lekcja (jeszcze raz): nie pozwól inżynierom spełniać wymagań. Znajdą najbardziej niejasną i skomplikowaną sprawę i podniosą ją do sprawy dominującej i wprowadzą wszystkich w błąd.