La codifica dei caratteri della tua locale (che puoi capire locale charmap
) è un multibyte per carattere.
Il più comune al giorno d'oggi è UTF-8 in cui i caratteri possono essere codificati da 1 a 4 byte. Non tutte le sequenze di byte formano caratteri validi in UTF-8. Ogni carattere non ASCII in UTF-8 inizia con un byte con i due bit più alti impostati e indica quanti byte seguono il set di bit più alto (ma non il secondo più alto).
/dev/urandom
contiene un flusso casuale di byte. tr
traslittera carattere, quindi deve decodificare quei byte come caratteri. Quei caratteri ASCII nel tuo intervallo sono tutti codificati su un carattere in UTF-8, ma tr
devono comunque decodificare tutti i caratteri. Esistono ad esempio altre codifiche multi-byte in cui alcuni caratteri diversi da quelli A
contengono il byte 0x41 (il codice per A
).
Perché quel flusso casuale di byte è destinato a contenere sequenze non valide (ad esempio un byte 0x80 da solo non è valido in UTF-8 poiché un carattere non ASCII deve iniziare con un byte maggiore di 0xc1 (0xc0 e 0xc1 non sono in UTF- 8 caratteri)), quindi tr
ritorna con un errore quando ciò accade.
Quello che vuoi qui è considerare quel flusso di byte come caratteri in una codifica che ha un byte per carattere. Quale scegliete non è importante come tutti quei personaggi nella vostra gamma (assumendo AZ, è significava ABCDEFGHIJKLMNOPQRSTUVWXYZ e non le cose come Ý
, Ê
) fanno parte del set di caratteri portatile in modo da codificare la stessa in tutti i set di caratteri supportati sul sistema.
Per questo, quando si imposta la LC_CTYPE
variabile di localizzazione, che è quella che decide quali set di caratteri viene utilizzato e quali cose come blank
, alpha
classi di personaggi contengono. Ma per la definizione dell'intervallo AZ, dovrai anche impostare la LC_COLLATE
variabile (quella che decide dell'ordinamento delle stringhe).
La locale C
aka POSIX
è quella che garantisce che i caratteri siano a byte singolo e AZ sia ABCDEFGHIJKLMNOPQRSTUVWXYZ. Potresti fare:
LC_CTYPE=C LC_COLLATE=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'
(qui spostare la -
fine, altrimenti, )-+
sarebbe come un intervallo come A-Z
)
Ma si noti che la LC_ALL
variabile sovrascrive tutti gli altri LC_*
e LANG
variabili. Quindi, se LC_ALL
altrimenti è già definito, quanto sopra non avrà alcun effetto. Quindi invece puoi semplicemente fare:
LC_ALL=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'
Ciò influirà su altre cose come la lingua dei messaggi di errore, ma comunque, cambiare LC_CTYPE potrebbe già essere stato un problema per i messaggi di errore (ad esempio, nessun modo di esprimere messaggi di errore russo o giapponese nel set di caratteri della locale C).
xargs
...