Сортировка не сортировка строк с трубкой '|' в этом правильно

17

Я пытаюсь отсортировать некоторые простые данные, разделенные каналом. Однако сортировка на самом деле не сортировка. Он перемещает строку заголовка вниз, но две строки, начинающиеся с 241, разделяются на строку, начинающуюся с 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

Заголовки столбцов перемещаются в конец файла, поэтому сортировка четко их обрабатывает. Но фактические значения сортируются не так, как я ожидал.

В этом случае я работал с этим

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

Но я чувствую, что в этом не должно быть необходимости. Почему сортировка не сортировка?

user10777668
источник
2
использовать LC_COLLATE=C sort. В зависимости от того, что вы ожидаете, вам также может понадобитьсяLC_COLLATE=C sort -t'|' -n
mosvy
3
Для сортировки данных «CSV в стиле» вы можете использовать csvsortс csvkit, который правильно обрабатывает кавычки значения.
Бакуриу

Ответы:

32

sort зависит от локали, поэтому в зависимости от настройки LC_COLLATE (которая унаследована от LANG) вы можете получить разные результаты:

$ 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

Это может вызвать проблемы в сценариях, потому что вы можете не знать, на что настроен вызывающий языковой стандарт, и поэтому можете получить разные результаты.

Сценарии нередко заставляют необходимые настройки

например

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

Теперь, что интересно, |персонаж выглядит странно.

Но это потому, что правило по умолчанию для en_US, которое происходит от ISO, говорит

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

Это означает, что |символ игнорируется, и порядок сортировки будет таким, как если бы символ не существовал.

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

И это соответствует "неожиданной" сортировке, которую вы видите.

Обходной путь - использовать -n(для принудительной сортировки чисел) или использовать разделитель полей (как вы это сделали) или использовать Cлокаль.

Стивен Харрис
источник
Захватывающий. Я видел некоторые другие хиты о локализации, но подумал, что это повлияет на относительный порядок 24 против 241, а не на что-то подобное.
user10777668
7
что-то еще полезное в сортировке GNU - это --debugопция, которая указывает ключ (подчеркнутый), используемый для сравнения
Джефф Шаллер
работа с параметром --debug просто подчеркивает всю строку - сортировка включает в себя символ канала, она просто не оказывает влияния из-за локализации. Это хорошая функция, но она не помогла мне в этом случае (я пытался :)
user10777668
Именно поэтому я упомянул об этом, @ user10777668 - он указывает, что sortиспользует всю строку вместо того, чтобы останавливаться на символах, которые мы предполагаем.
Джефф Шаллер
Я не ожидал, что это остановится. Я ожидал, что он распознает символ канала и включит его в сортировку, поэтому трактует 24 | 1 и 241 по-разному. Я не уверен, как --debug изменил бы это, и фактически, учитывая, что он подчеркивает | Похоже, что это активно отвлекло бы от реальной проблемы, когда локализация привела к вводу символа канала
user10777668
1

Что меня раздражает, так это то, что 24они не сдвигаются с места между ними 241. Второе поле начинается с 1. При попытке сортировки с ведущим 4во втором поле, поле 24перемещается вниз, поэтому я подозреваю, sortчто просто игнорирует, |если не указано иное. Попробуй sort -n...

Рудик
источник
1

-n, --numeric-sort сравнить по числовому значению строки

210
23

Без -n, 210 по тексту опережает 23 по характеру моего персонажа.

michaelkrieger
источник
Вы правы, но это не объясняет, что трубочный чарс отличается от других. Другие ответы показывают, что из-за локали канал рассматривается как не существующий, поэтому следующая цифра определяет порядок.
Кригги