Кодування символів вашої мови (про яке ви можете розповісти locale charmap ) є багатобайтовим на кожний символ.
Найпоширенішим на сьогоднішній день є UTF-8, де символи можуть кодуватися більше від 1 до 4 байтів. Не всі послідовності байтів утворюють дійсні символи в UTF-8. Кожен символ, що не є ASCII в UTF-8, починається з одного байта, який має два найвищі біти, і повідомляє, скільки байтів з найвищим (але не другим найвищим) набором бітів слідує.
/dev/urandomмістить випадковий потік байтів. trтранслітерація символів, тому йому потрібно розшифрувати ці байти як символи. Ці символи ASCII у вашому діапазоні всі закодовані в одному символі в UTF-8, але trвсе ж потрібно декодувати всі символи. Наприклад, є інші багатобайтові кодування, де деякі символи, крім Aмістять байт 0x41 (код дляA ).
Оскільки цей випадковий потік байтів повинен містити недійсні послідовності (наприклад, байт 0x80 сам по собі недійсний у UTF-8, оскільки символ, який не є ASCII, повинен починатися з байта, що перевищує 0xc1 (0xc0 і 0xc1 не містять UTF- 8 символів)), тому trповертається з помилкою, коли це відбувається.
Що ви хочете тут, це вважати цей потік байтів як символи в кодуванні, який має один байт на символ. Що б ви не вибрали, це не важливо, оскільки всі ці символи у вашому діапазоні (якщо припустити, AZ, ви мали на увазі ABCDEFGHIJKLMNOPQRSTUVWXYZ, а не подібні речі Ý, Ê) є частиною портативного набору символів, тому кодуйте однаково у всіх шаблонах, що підтримуються у вашій системі.
Для цього, потрібно встановити LC_CTYPEзмінну локалізації , яка є той , який вирішує , який набір символів використовується і то , що такі речі , як blank, alphaсимвольні класи містять. Але для визначення діапазону AZ ви також хочете встановитиLC_COLLATE змінну (ту, яка вирішує впорядкування рядків).
CАка POSIXлокаль одне , що гарантує символи в поодинокі байти і AZ є АБВГДЕЖЗІКЛМНОПРСТУФХЧШЕЮЯ. Ви можете зробити:
LC_CTYPE=C LC_COLLATE=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'
(тут переміщення -до кінця, інакше, )-+сприймається як діапазон, якA-Z )
Але зауважте, що LC_ALLзмінна перекриває всі інші LC_*та LANGзмінні. Отже, якщо LC_ALLінше вже визначено, вищесказане не матиме ефекту. Тож замість цього ви можете просто зробити:
LC_ALL=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'
Це вплине на інші речі, такі як мова повідомлень про помилки, але у будь-якому разі зміна LC_CTYPE вже могла бути проблемою для повідомлень про помилки (наприклад, жодним чином висловити російські чи японські повідомлення про помилки в графіку локальної мови C).
xargs…