Perché l'ordinamento ignora i caratteri non alfanumerici?


25

Quando si ordinano i nomi dei file, lsignora i caratteri come -,_. Mi aspettavo che usasse quei personaggi anche nell'ordinamento.

Un esempio:

touch a1 a2 a-1 a-2 a_1 a_2 a.1 a.2 a,1 a,2

Ora mostra questi file con ls -1:

a1
a_1
a-1
a,1
a.1
a2
a_2
a-2
a,2
a.2

Quello che mi aspettavo era qualcosa del genere:

a1
a2
a,1
a,2
a.1
a.2
a_1
a_2
a-1
a-2

cioè mi aspettavo che i caratteri non alfanumerici fossero presi in considerazione durante l'ordinamento.

Qualcuno può spiegare questo comportamento? Questo comportamento è richiesto da uno standard? O è dovuto alla codifica UTF-8?

Aggiornamento: sembra che questo sia correlato all'ordinamento UTF-8:

$ LC_COLLATE=C ls -1
a,1
a,2
a-1
a-2
a.1
a.2
a1
a2
a_1
a_2

2
UTF-8 e ASCII sono identici se tutto ciò che stai usando sono i primi 128 punti di codice (che è il tuo esempio). Cosa succede se lo fai LC_COLLATE=C ls?
Alexios

Il problema non è che ASCII e UTF-8 sono identici, è piuttosto che UTF-8 ha le sue regole di fascicolazione (ordinamento).
daniel kullmann,

1
Sì, è vero che [_-,.]vengono raggruppati e in qualche modo semi ignorati. Non so esattamente come o dove sia definito tale confronto, ma deve essere un problema di confronto, perché semplicemente e solo, cambiare il confronto in C (via LC_COLLATE=C ls -l) è sufficiente per darti l'ordinamento che ti aspettavi (supponendo che LC_ALLsia non prevalente LC_COLLATE). Questo vale per l'intera gamma di caratteri nel piano multilingue Unicode Basic ... Ho modificato la mia risposta per includere uno script di esempio che lo
confermi

se non ti piace come funziona, puoi creare un alias e inserirlo nel tuo ~ / .profile: alias ls = 'LC_COLLATE = C ls' </kbd>
jippie

Risposte:


10

Questo non ha nulla a che fare con il set di caratteri. Piuttosto, è la lingua che determina l'ordine di confronto. La libc esamina la lingua presentata in $LC_COLLATE/ $LC_ALL/ $LANGe cerca le sue regole di confronto (ad es. /usr/share/i18n/locales/*Per GLibC) e ordina il testo come indicato.


FYI: È più complicato di così. Se ne usassi uno, ad strcollesempio, vedresti che qualcosa del genere aasa.cverrebbe ordinato sopra aas.c.
Don Scott,

12

EDIT: test aggiunto per i dati ordinati con LC_COLLATE = C


La sequenza di fascicolazione predefinita tratta quei caratteri di "punteggiatura" come uguali Use LC_COLLATE=Cper trattarli in ordine di punti di codice.

for i in 'a1' 'a_1' 'a-1' 'a,1' 'a.1' 'a2' 'a_2' 'a-2' 'a,2' 'a.2' ;do
  echo $i; 
done |LC_COLLATE=C sort

Produzione

a,1
a,2
a-1
a-2
a.1
a.2
a1
a2
a_1
a_2

Il codice seguente verifica tutti i caratteri UTF-8 validi nel piano multilingue di base (tranne per \ x00 e \ x0a ; per semplicità)
confronta un file in una sequenza ascendente nota (generata), con quel file ordinato casualmente e poi riordinato con LC_COLLATE = C. Il risultato mostra che la sequenza C è identica alla sequenza generata originale.

{ i=0 j=0 k=0 l=0
  for i in {0..9} {A..F} ;do
  for j in {0..9} {A..F} ;do
  for k in {0..9} {A..F} ;do
  for l in {0..9} {A..F} ;do
     (( 16#$i$j$k$l == 16#0000 )) && { printf '.' >&2; continue; }
     (( 16#$i$j$k$l == 16#000A )) && { printf '.' >&2; continue; }
     (( 16#$i$j$k$l >= 16#D800    && 
        16#$i$j$k$l <= 16#DFFF )) && { printf '.' >&2; continue; }
     (( 16#$i$j$k$l >= 16#FFFE )) && { printf '.' >&2; continue; }
     echo 0x"$i$j$k$l" |recode UTF-16BE/x4..UTF-8 || { echo "ERROR at codepoint $i$j$k$l " >&2; continue; } 
     echo 
  done
  done
  done; echo -n "$i$j$k$l " >&2
  done; echo >&2
} >listGen

             sort -R listGen    > listRandom
LC_COLLATE=C sort    listRandom > listCsort 

diff <(cat listGen;   echo "last line of listOrig " ) \
     <(cat listCsort; echo "last line of listCsort" )
echo 
cmp listGen listCsort; echo 'cmp $?='$?

Produzione:

63485c63485
< last line of listOrig 
---
> last line of listCsort

cmp $?=0

2
Dove è documentato? Fa parte dello standard Unicode?
daniel kullmann,

2
In realtà, non ottengono lo stesso valore; quei personaggi vengono semplicemente ignorati durante l'ordinamento. Se fossero trattati con un valore uguale, l'ordinamento a_1 a2 a_2sarebbe impossibile.
daniel kullmann,

+1 per il tuo duro lavoro e codice di esempio. Dopo molte ore l'ordinamento dei nomi di directory con punteggiatura per adattarsi al modo in treecui penso che ci sia qualcosa di più nella storia come la punteggiatura che viene rimossa dalle stringhe di confronto o qualcosa del genere. Posso dire che il /personaggio deve essere impostato come il personaggio più basso nella sequenza di confronto, non importa cos'altro.
WinEunuuchs2Unix
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.