La codificación de caracteres de su localidad (con la que se puede decir locale charmap
) es de varios bytes por carácter.
El más común hoy en día es UTF-8, donde los caracteres se pueden codificar de 1 a 4 bytes. No todas las secuencias de bytes forman caracteres válidos en UTF-8. Cada carácter no ASCII en UTF-8 comienza con un byte que tiene los dos bits más altos establecidos y le dice cuántos bytes siguen con el juego de bits más alto (pero no el segundo más alto).
/dev/urandom
contiene una secuencia aleatoria de bytes. tr
translitera el carácter, por lo que necesita decodificar esos bytes como caracteres. Esos caracteres ASCII en su rango están codificados en un solo carácter en UTF-8, pero tr
aún necesita decodificar todos los caracteres. Hay, por ejemplo, otras codificaciones de varios bytes donde algunos caracteres que no A
contienen el byte 0x41 (el código para A
).
Debido a que ese flujo aleatorio de bytes está obligado a contener secuencias no válidas (por ejemplo, un byte 0x80 por sí mismo no es válido en UTF-8 ya que un carácter no ASCII tiene que comenzar con un byte mayor que 0xc1 (0xc0 y 0xc1 no están en UTF- 8 caracteres)), por lo que tr
vuelve con un error cuando eso sucede.
Lo que quiere aquí es considerar esa secuencia de bytes como caracteres en una codificación que tiene un byte por carácter. Lo que elija no es importante ya que todos esos caracteres en su rango (suponiendo que AZ, se refería a ABCDEFGHIJKLMNOPQRSTUVWXYZ y no cosas como Ý
, Ê
) son parte del conjunto de caracteres portátil, por lo que debe codificarse de la misma manera en todos los conjuntos de caracteres admitidos en su sistema.
Por eso, lo haces con la LC_CTYPE
variable de localización, que es el que decide qué juego de caracteres que se utilizan y qué cosas como blank
, alpha
clases de personajes contienen. Pero para la definición del rango AZ, también querrá establecer la LC_COLLATE
variable (la que decide el orden de las cadenas).
La configuración regional C
aka POSIX
es aquella que garantiza que los caracteres son de un solo byte y AZ es ABCDEFGHIJKLMNOPQRSTUVWXYZ. Podrías hacerlo:
LC_CTYPE=C LC_COLLATE=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'
(aquí mover el -
al final, de lo contrario, )-+
se tomaría como un rango como A-Z
)
Pero tenga en cuenta que la LC_ALL
variable anula todas las demás LC_*
y LANG
variables. Entonces, si LC_ALL
ya está definido de otra manera, lo anterior no tendrá efecto. Entonces, en su lugar, simplemente puede hacer:
LC_ALL=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'
Eso afectará otras cosas como el idioma de los mensajes de error, pero de todos modos, cambiar LC_CTYPE ya podría haber sido un problema para los mensajes de error (por ejemplo, no hay forma de expresar mensajes de error en ruso o japonés en el conjunto de caracteres de la configuración regional C).
xargs
...