Ordina non ordinare le linee con una pipe "|" in esso correttamente


17

Sto cercando di ordinare alcuni semplici dati delimitati da pipe. Tuttavia, l'ordinamento non è in realtà l'ordinamento. Sposta la mia riga di intestazione in basso, ma le mie due righe che iniziano con 241 vengono divise da una riga che inizia con 24.

cat sort_fail.csv
column_a|column_b|column_c
241|212|20810378
24|121|2810172
241|213|20810376

sort sort_fail.csv
241|212|20810378
24|121|2810172
241|213|20810376
column_a|column_b|column_c

Le intestazioni di colonna vengono spostate nella parte inferiore del file, quindi l'ordinamento lo sta chiaramente elaborando. Ma i valori effettivi non vengono ordinati come mi aspetterei.

In questo caso ho lavorato con esso

sort sort_fail.csv --field-separator='|' -k1,1

Ma penso che non dovrebbe essere necessario. Perché l'ordinamento non è l'ordinamento?


2
usare LC_COLLATE=C sort. A seconda di cosa ti aspetti, potresti anche aver bisognoLC_COLLATE=C sort -t'|' -n
mosvy,

3
Per ordinare i dati "stile CSV" si consiglia di utilizzare csvsortda csvkit, che gestisce i valori correttamente citato.
Bakuriu,

Risposte:


32

sort è a conoscenza delle impostazioni locali, quindi a seconda dell'impostazione LC_COLLATE (che è ereditata da LANG) potresti ottenere risultati diversi:

$ LANG=C sort sort_fail.csv 
241|212|20810378
241|213|20810376
24|121|2810172
column_a|column_b|column_c

$ LANG=en_US sort sort_fail.csv
241|212|20810378
24|121|2810172
241|213|20810376
column_a|column_b|column_c

Ciò può causare problemi negli script, perché potresti non essere a conoscenza delle impostazioni locali della chiamata e quindi ottenere risultati diversi.

Non è raro che gli script forzino l'impostazione necessaria

per esempio

$ grep 'LC.*sort' /bin/precat
      LC_COLLATE=C sort -u | prezip-bin -z "$cmd: $2"

Ora, ciò che è interessante, qui, è che il |personaggio sembra strano.

Ma questo perché dice la regola predefinita per en_US, che deriva da ISO

$ grep 007C /usr/share/i18n/locales/iso14651_t1_common
<U007C> IGNORE;IGNORE;IGNORE;<j> # 142 |

Ciò significa che il |personaggio viene ignorato e l'ordinamento sarebbe come se il personaggio non esistesse.

$ tr -d '|' < sort_fail.csv | LANG=C sort
24121220810378
241212810172
24121320810376
column_acolumn_bcolumn_c

E questo corrisponde all'ordinamento "inaspettato" che stai vedendo.

Le soluzioni alternative sono utilizzare -n(per forzare gli ordinamenti numerici) o utilizzare il separatore di campi (come è stato fatto in precedenza) o utilizzare le Cimpostazioni internazionali.


Affascinante. Ho visto altri successi sulla localizzazione, ma ho pensato che avrebbe avuto un impatto sul relativo ordinamento di 24 vs 241, non qualcosa del genere.
user10777668

7
qualcosa di molto utile nell'ordinamento GNU è l' --debugopzione, che indica la chiave (sottolineata) usata per confrontare
Jeff Schaller

l'esecuzione con --debug sottolinea solo l'intera riga - l'ordinamento include il carattere pipe, è impostato per non avere alcun impatto a causa della localizzazione. È una buona funzionalità ma in questo caso non mi ha aiutato (ho provato :)
user10777668

Questo è esattamente il motivo per cui l'ho menzionato, @ user10777668 - indica che sortsta usando l'intera riga invece di fermarsi ai caratteri che supponiamo che sia.
Jeff Schaller

Non mi aspettavo che finisse. Mi aspettavo che riconoscesse il carattere pipe e lo includesse nell'ordinamento, quindi trattando 24 | 1 e 241 in modo diverso. Non sono sicuro di come --debug lo avrebbe cambiato, e in effetti dato che sottolinea il | sembra che avrebbe attivamente distratto dal vero problema in cui la localizzazione ha portato al
ripristino del

1

Ciò che mi irrita è che il 24non si sposta dal suo posto tra i due 241. Il secondo campo inizia con a 1. Provando l'ordinamento con un vantaggio 4nel secondo campo, 24viene spostato verso il basso, quindi sospetto sortsemplicemente ignori il |se non diversamente specificato. Prova sort -n...


1

-n, --numeric-sort compare in base al valore numerico della stringa

210
23

Senza il -n, 210 per testo è avanti di 23 come va carattere mio.


Hai ragione, ma questo non spiega che il carattere del pipe sia diverso. Le altre risposte mostrano che, a causa delle impostazioni locali, la pipe viene trattata come non presente, quindi la cifra successiva è ciò che decide l'ordinamento.
Criggie,
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.