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/urandom
zawiera losowy strumień bajtów. tr
transliteruje znak, więc musi dekodować te bajty jako znaki. Wszystkie znaki ASCII z twojego zakresu są zakodowane na jednym znaku w UTF-8, ale tr
nadal muszą dekodować wszystkie znaki. Istnieją na przykład inne kodowania wielobajtowe, w których niektóre znaki inne niż A
zawierają 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 tr
powraca 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_CTYPE
zmienną lokalizacji, która jest tym, który decyduje, które charset jest używany i co takie rzeczy blank
, alpha
klas postaci zawierać. Ale dla definicji zakresu AZ będziesz również chciał ustawić LC_COLLATE
zmienną (tę, która decyduje o kolejności ciągów).
C
Aka POSIX
locale 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_ALL
zmienna zastępuje wszystkie pozostałe LC_*
i LANG
zmienne. Tak więc, jeśli LC_ALL
inaczej 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
...