Dlaczego tr nie może czytać z / dev / urandom na OSX?

35

Kolega zaproponował utworzenie losowego klucza za pomocą następującego polecenia:

tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 32 | xargs

Dał mi błąd:

tr: niedozwolona sekwencja bajtów

Obawiam się, że nie mam /dev/urandomw moim systemie. Próbowałem google, aby dowiedzieć się, jak zainstalować ten plik, ale wyszedłem pusty. Próbowałem locate urandomi też wyszedłem pusty. (no cóż, właściwie znalazł stronę man, ale to nie pomaga)

Jak mogę urandomudostępnić w moim systemie Mac OSX? (Lew)

Kirk Woll
źródło
3
Ciekawe wykorzystanie xargs...
sendmoreinfo

Odpowiedzi:

49

Na podstawie otrzymanego komunikatu o błędzie nie sądzę, że problem dotyczy / dev / urandom. Gdyby tak było, oczekiwałbym błędu typu „brak takiego pliku lub katalogu”.

Poszukałem otrzymanego komunikatu o błędzie, który wydaje się być odpowiedni dla Twojego problemu: http://nerdbynature.de/s9y/2010/04/11/tr-Illegal-byte-sequence

Zasadniczo określ ustawienia regionalne, poprzedzając trpolecenie za pomocą LC_CTYPE=C:

LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 32 | xargs
Łk
źródło
Dzięki, to naprawdę załatwiło sprawę. Masz pomysł, dlaczego nie mogę znaleźć urandomlub random? Czy są to specjalne magiczne „pliki”, które nie istnieją w rzeczywistym systemie plików? (Również zasugerowałem edycję, aby złagodzić gnicie linków)
Kirk Woll,
1
Uważam, locateże nie przeszukuje bezpośrednio twojego systemu plików, a raczej wyszukuje zapytanie przy użyciu wstępnie zbudowanej bazy danych. Ta baza danych jest najprawdopodobniej skonfigurowana do ignorowania / dev / i innych „specjalnych” systemów plików.
Łk-
w porządku, ale nie widzę tego, kiedy patrzę bezpośrednio /dev. Domyśl. Ale jeszcze raz dziękuję za pomoc.
Kirk Woll,
1
wydaje się nie działać na 10.9; nadal występuje błąd z tym samym komunikatem o błędzie. LC_ALL=Czałatwia sprawę.
Erik Allik
1
Zmień ten link na nerdbynature.de/s9y/2010/04/11/tr-Illegal-byte-sequence, ponieważ obecnie wskazuje na najnowszą stronę blogu niezawierającą trinformacji.
Jeroen Wiert Pluimers
11

Twoje trpróby interpretacji jego danych wejściowych jako tekstu w kodowaniu UTF-8. Będzie więc narzekał i przerywał pierwszą sekwencję bajtów, która nie jest poprawna UTF-8. Prefiks trz LC_ALL=Club LC_CTYPE=Cspowoduje wyeksportowanie tej zmiennej do środowiska tr, zmieniając w ten sposób jej koncepcję lokalnego zestawu znaków na standard C, tzn. Wszystko jest tylko sekwencją nieprzezroczystych bajtów.

Nawiasem mówiąc, czy sekwencja \)-+w twoim poleceniu jest celowa? Dotyczy to *również tego, co już uwzględniłeś, ale nie obejmuje -siebie, jak mogłeś sobie wyobrazić. Zamiast tego lepiej napisać jeden z nich:

LC_ALL=C tr -dc 'A-Za-z0-9_!@#$%^&*()\-+=' < /dev/urandom
LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)\\-+= < /dev/urandom
MvG
źródło
6

Jak zauważyli inni, problemu nie /dev/urandombrakuje, ale raczej to, jak trdziała system OS X. Zamiast bawić się różnymi wariantami środowiska, użyj perlzamiast tr:

perl -pe 'binmode(STDIN, ":bytes"); tr/A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+=//dc;' < /dev/urandom | head -c 32; echo

Ma to tę zaletę, że jest przenośny w systemach OS X, Redhat i Ubuntu.

(Usunąłem również potok xargs, zastępując czarownicę echo, aby uzyskać nowy wiersz na końcu wyjścia).

Trenton
źródło
Wcześniej czy później spodziewam się, że Perl wprowadzi binmode ":utf8"standard, w którym to momencie twoje rozwiązanie Perla będzie miało ten sam problem, trco on.
Mark
Rozwiązano problem Marka poprzez dodanie binmode (STDIN, „: bytes”) do próbki kodu.
Trenton
2

Po pierwsze, czy zamierzałeś umieścić -lub *na liście prawidłowych znaków? Parametr trobejmujący sekwencję, )-+który oznacza „zakres bajtów rozpoczynający się )i kończący na +, który jest w rzeczywistości )*+.

Po drugie, zamiast odczytywać wiele kilobajtów z puli entropii jądra (a tym samym oznaczać całą pulę jako niepewną, co wpłynie na wszelkie inne procesy wymagające bezpiecznej entropii), rozważ odczyt tylko tyle bitów, ile potrzebujesz: użyj head -c...jako pierwszego kroku, a następnie tłumaczyć, zamiast odrzucać niechciane postacie.

Ta szczególna wersja problemu jest nieco niezwykła, ponieważ używa 76 różnych symboli; większość po prostu chce alfanumerycznych, więc jeśli będziesz zadowolony tylko z 64 symboli, to użycie base64narzędzia zminimalizuje zużycie puli entropii (zauważ, że 24 to 6/8 z 32):

head -c24 < /dev/random | base64
Martin Kealey
źródło
1

Kodowanie znaków twojego regionu (które możesz rozpoznać locale charmap) jest wielobajtowe na znak.

Najpopularniejszym obecnie jest UTF-8, w którym znaki mogą być zakodowane w zakresie od 1 do 4 bajtów. Nie wszystkie sekwencje bajtów tworzą prawidłowe znaki w UTF-8. Każdy znak inny niż ASCII w UTF-8 zaczyna się od jednego bajtu, który ma dwa najwyższe ustawione bity i mówi, ile bajtów ma najwyższy (ale nie drugi najwyższy) zestaw bitów.

/dev/urandomzawiera losowy strumień bajtów. trtransliteruje znak, więc musi dekodować te bajty jako znaki. Wszystkie znaki ASCII z twojego zakresu są zakodowane na jednym znaku w UTF-8, ale trnadal muszą dekodować wszystkie znaki. Istnieją na przykład inne kodowania wielobajtowe, w których niektóre znaki inne niż Azawierają bajt 0x41 (kod dla A).

Ponieważ ten losowy strumień bajtów musi zawierać nieprawidłowe sekwencje (na przykład sam bajt 0x80 jest niepoprawny w UTF-8, ponieważ znak spoza ASCII musi zaczynać się bajtem większym niż 0xc1 (0xc0 i 0xc1 nie ma UTF- 8 znaków)), więc trpowraca z błędem, gdy tak się dzieje.

To, czego chcesz tutaj, to wziąć pod uwagę ten strumień bajtów jako znaków w kodowaniu, które ma jeden bajt na znak. Cokolwiek wybierzesz, nie jest ważne, ponieważ wszystkie te znaki z twojego zakresu (zakładając, że AZ miał na myśli ABCDEFGHIJKLMNOPQRSTUVWXYZ, a nie rzeczy takie jak Ý, Ê) są częścią przenośnego zestawu znaków, więc koduj to samo we wszystkich zestawach znaków obsługiwanych w twoim systemie.

Do tego, można ustawić LC_CTYPEzmienną lokalizacji, która jest tym, który decyduje, które charset jest używany i co takie rzeczy blank, alphaklas postaci zawierać. Ale dla definicji zakresu AZ będziesz również chciał ustawić LC_COLLATEzmienną (tę, która decyduje o kolejności ciągów).

CAka POSIXlocale to taki, który gwarantuje znaki są jedno- bajtów i AZ jest ABCDEFGHIJKLMNOPQRSTUVWXYZ. Mógłbyś:

 LC_CTYPE=C LC_COLLATE=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'

(tutaj przesuwanie -do końca, w przeciwnym razie )-+byłoby przyjmowane jako zasięg podobny do A-Z)

Należy jednak pamiętać, że LC_ALLzmienna zastępuje wszystkie pozostałe LC_*i LANGzmienne. Tak więc, jeśli LC_ALLinaczej jest już zdefiniowane, powyższe nie przyniesie efektu. Zamiast tego możesz po prostu zrobić:

 LC_ALL=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'

Wpłynie to na inne rzeczy, takie jak język komunikatów o błędach, ale w każdym razie zmiana LC_CTYPE mogła już stanowić problem w przypadku komunikatów o błędach (na przykład brak możliwości wyrażenia rosyjskich lub japońskich komunikatów o błędach w zestawie znaków regionu C).

Stéphane Chazelas
źródło
0

Według strony man , / dev / random jest prawdopodobnie będzie wystarczający dla Twoich potrzeb. Być może Apple przestało tworzyć / dev / urandom, ponieważ jest to niepotrzebne?

jsbillings
źródło
Ja też nie mam /dev/random.
Kirk Woll,
MacOSX powinien mieć zarówno / dev / random i / dev / urandom. Być może Apple nie zawiera już tych specjalnych plików? A może jest tam tylko, jeśli zainstalujesz XCode?
jsbillings
1
FWIW, oba urządzenia są obecne na mojej stacji roboczej z uaktualnionym Lion do Mountain Lion. Wierzę, że był również obecny na Lionie. Węzły są również różne (13,0 vs. 13,1)
mrb