Voglio rimuovere le righe duplicate da un file con parole di script siriano. Il file sorgente ha 3 righe, la prima e la terza sono identiche.
$ cat file.txt
ܐܒܘܢ
ܢܗܘܐ
ܐܒܘܢ
Quando uso sort
e uniq
, il risultato presume che tutte e 3 le righe siano identiche, il che è sbagliato:
$ cat file.txt | sort | uniq -c
3 ܐܒܘܢ
Anche l'impostazione esplicita della localizzazione su Syriac non aiuta.
$ LC_COLLATE=syr_SY.utf8 cat file.txt | sort | uniq -c
3 ܐܒܘܢ
Perché dovrebbe succedere?
Sto usando Kubuntu 18 e bash, se è importante.
Risposta accettata:
L'implementazione GNU di uniq
come si trova su Ubuntu, con -c
, non riporta i conteggi di identici contigui righe ma conteggi di righe contigue che ordinano lo stesso¹.
La maggior parte delle localizzazioni internazionali sui sistemi GNU ha quel bug che molti caratteri completamente non correlati sono stati definiti con lo stesso ordinamento, la maggior parte di essi perché il loro ordinamento non è affatto definito. La maggior parte degli altri sistemi operativi si assicura che tutti i caratteri abbiano un ordine di ordinamento diverso.
$ expr ܐ = ܒ
1
(expr
's =
operatore, per argomenti che non sono numerici, restituisce 1 se gli operandi ordinano allo stesso modo, 0 altrimenti).
È lo stesso con ar_SY.UTF-8
o en_GB.UTF-8
.
Ciò di cui avresti bisogno è un locale in cui a quei personaggi sia stato assegnato un ordine di ordinamento diverso. Se Ubuntu avesse le impostazioni locali per la lingua siriana, potresti aspettarti che a quei caratteri sia stato assegnato un ordine di ordinamento diverso, ma Ubuntu non ha tali impostazioni locali.
Puoi guardare l'output di locale -a
per un elenco delle localizzazioni supportate. Puoi abilitare più locali eseguendo dpkg-reconfigure locales
come root
. Puoi anche definire più locali manualmente usando localedef
in base ai file di definizione in /usr/share/i18n/locales
, ma lì non troverai dati per la lingua siriaca.
Nota che in:
LC_COLLATE=syr_SY.utf8 cat file.txt | sort | uniq -c
Stai solo impostando la variabile LC_COLLATE per il cat
comando (che non influisce sul modo in cui restituisce il contenuto del file, cat
non si preoccupa delle regole di confronto e nemmeno della codifica dei caratteri in quanto non è un'utilità di testo). Vorresti impostarlo per entrambi sort
e uniq
. Vorresti anche impostare LC_CTYPE
a una locale che ha un set di caratteri UTF-8.
Poiché il tuo sistema non ha syr_SY.utf8
locale, è lo stesso che usare il C
locale (il locale predefinito).
In realtà, qui il locale C o C.UTF-8 è probabilmente il locale che vorresti usare.
In quelle impostazioni locali, l'ordine di confronto si basa sul punto di codice, punto di codice Unicode per C.UTF-8, valore di byte per C, ma finisce per essere lo stesso della codifica dei caratteri UTF-8 che ha quella proprietà.
$ LC_ALL=C expr ܐ = ܒ
0
$ LC_ALL=C.UTF-8 expr ܐ = ܒ
0
Quindi con:
(export LANG=ar_SY.UTF-8 LC_COLLATE=C.UTF-8 LANGUAGE=syr:ar:en
unset LC_ALL
sort <file | uniq -c)
Avresti un LC_CTYPE con UTF-8 come set di caratteri, un ordine di confronto basato sul punto di codice e le altre impostazioni rilevanti per la tua regione, quindi ad esempio messaggi di errore in siriaco o arabo se GNU coreutils sort
o uniq
i messaggi erano stati tradotti in quelle lingue (non l'hanno ancora fatto).
Se non ti interessano quegli altri impostazioni, è altrettanto facile (e anche più portatile) da usare:
<file LC_ALL=C sort | LC_ALL=C uniq -c
Oppure
(export LC_ALL=C; <file sort | uniq -c)
come ha già mostrato @isaac.