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).
xargs...