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.