A codificação de caracteres da localidade (com a qual você pode contar locale charmap
) é de vários bytes por caractere.
Atualmente, o mais comum é o UTF-8, onde os caracteres podem ser codificados com mais de 1 a 4 bytes. Nem todas as seqüências de bytes formam caracteres válidos em UTF-8. Todo caractere não ASCII do UTF-8 começa com um byte com os dois bits mais altos definidos e informa quantos bytes com o conjunto de bits mais alto (mas não o segundo mais alto) a seguir.
/dev/urandom
contém um fluxo aleatório de bytes. tr
translitera caracteres, portanto, é necessário decodificar esses bytes como caracteres. Esses caracteres ASCII no seu intervalo são todos codificados em um caractere em UTF-8, mas tr
ainda precisam decodificar todos os caracteres. Por exemplo, existem outras codificações de vários bytes em que alguns caracteres que não A
contêm o byte 0x41 (o código para A
).
Como esse fluxo aleatório de bytes deve conter sequências inválidas (por exemplo, um byte de 0x80 é inválido em UTF-8, pois um caractere não ASCII deve iniciar com um byte maior que 0xc1 (0xc0 e 0xc1 não possui UTF- 8 caracteres)), então tr
retorna com um erro quando isso acontece.
O que você deseja aqui é considerar esse fluxo de bytes como caracteres em uma codificação que possui um byte por caractere. Seja qual você escolher não é importante como todos os personagens em sua faixa (assumindo por AZ, você significou ABCDEFGHIJKLMNOPQRSTUVWXYZ e não coisas como Ý
, Ê
) fazem parte do conjunto de caracteres portátil para ser codificado o mesmo em todos os conjuntos de caracteres suportados no sistema.
Para isso, você deve definir a LC_CTYPE
variável localização, que é a que decide qual charset é usado eo que coisas como blank
, alpha
classes de personagens conter. Mas para a definição do intervalo AZ, você também desejará definir a LC_COLLATE
variável (a que decide a ordem das strings).
O C
código de POSIX
idioma aka é aquele que garante que os caracteres sejam bytes únicos e AZ é ABCDEFGHIJKLMNOPQRSTUVWXYZ. Você poderia fazer:
LC_CTYPE=C LC_COLLATE=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'
(aqui, mover o -
para o final, caso contrário, )-+
seria aceito como um intervalo A-Z
)
Mas observe que a LC_ALL
variável substitui todas as outras LC_*
e LANG
variáveis. Portanto, se LC_ALL
já estiver definido de outra forma, o acima não terá efeito. Então, você pode simplesmente fazer:
LC_ALL=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'
Isso afetará outras coisas, como o idioma das mensagens de erro, mas, de qualquer maneira, alterar LC_CTYPE já pode ter sido um problema para mensagens de erro (por exemplo, nenhuma maneira de expressar mensagens de erro em russo ou japonês no conjunto de caracteres do código de idioma C).
xargs
...