Mã hóa ký tự của miền địa phương của bạn (mà bạn có thể biết với locale charmap
) là nhiều byte cho mỗi ký tự.
Phổ biến nhất hiện nay là UTF-8 nơi các ký tự có thể được mã hóa trên 1 đến 4 byte. Không phải tất cả các chuỗi byte tạo thành các ký tự hợp lệ trong UTF-8. Mỗi ký tự không phải ASCII trong UTF-8 bắt đầu bằng một byte có hai bit cao nhất được đặt và cho biết có bao nhiêu byte với bit cao nhất (nhưng không cao thứ hai) được đặt theo sau.
/dev/urandom
chứa một luồng byte ngẫu nhiên. tr
phiên âm ký tự, vì vậy nó cần giải mã các byte đó thành ký tự. Các ký tự ASCII trong phạm vi của bạn đều được mã hóa trên một ký tự trong UTF-8, nhưng tr
vẫn cần giải mã tất cả các ký tự. Ví dụ, có các mã hóa nhiều byte khác trong đó một số ký tự khác không A
chứa byte 0x41 (mã cho A
).
Bởi vì luồng byte ngẫu nhiên đó bị ràng buộc để chứa các chuỗi không hợp lệ (ví dụ, chính byte 0x80 không hợp lệ trong UTF-8 vì một ký tự không phải ASCII phải bắt đầu bằng một byte lớn hơn 0xc1 (0xc0 và 0xc1 không có UTF- 8 ký tự)), do đó tr
trả về với một lỗi khi điều đó xảy ra.
Những gì bạn muốn ở đây là xem luồng byte đó là các ký tự trong một mã hóa có một byte cho mỗi ký tự. Bất cứ điều gì bạn chọn đều không quan trọng vì tất cả các ký tự trong phạm vi của bạn (giả sử là AZ, bạn có nghĩa là ABCDEFGHIJKLMNOPQRSTUVWXYZ và không phải những thứ như Ý
, Ê
) là một phần của bộ ký tự di động được mã hóa giống nhau trong tất cả các bảng mã được hỗ trợ trên hệ thống của bạn.
Vì thế, bạn sẽ đặt LC_CTYPE
biến nội địa hóa là biến quyết định bộ ký tự nào được sử dụng và những thứ như thế nào blank
, alpha
các lớp ký tự chứa. Nhưng đối với định nghĩa của phạm vi AZ, bạn cũng sẽ muốn đặt LC_COLLATE
biến (biến quyết định thứ tự chuỗi).
Các C
aka POSIX
locale là một trong đó đảm bảo nhân vật đơn byte và AZ là ABCDEFGHIJKLMNOPQRSTUVWXYZ. Bạn có thể làm:
LC_CTYPE=C LC_COLLATE=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'
(ở đây di chuyển -
đến cuối, nếu không, )-+
sẽ được coi là một phạm vi như A-Z
)
Nhưng lưu ý rằng LC_ALL
biến này ghi đè tất cả các biến khác LC_*
và LANG
biến. Vì vậy, nếu LC_ALL
đã được xác định khác, ở trên sẽ không có hiệu lực. Vì vậy, thay vào đó bạn chỉ có thể làm:
LC_ALL=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'
Điều đó sẽ ảnh hưởng đến những thứ khác như ngôn ngữ của thông báo lỗi, nhưng dù sao, việc thay đổi LC_CTYPE có thể đã gây ra sự cố cho thông báo lỗi (ví dụ: không có cách nào để thể hiện thông báo lỗi tiếng Nga hoặc tiếng Nhật trong bảng mã của ngôn ngữ C).
xargs
...