Тип UNIX игнорирует пробелы

Вот быстрый вопрос.

Для файла txt:

ab
a c
a a

При вызове sort txt я получаю:

a a
ab
a c

Другими словами, это не правильная сортировка, она вроде удаляет/игнорирует пробелы! Я ожидал, что это поведение sort -i, но это происходит с флагом -i или без него.

Я хотел бы получить "правильную" сортировку:

a a
a c
ab

Как мне это сделать?

Ответ 1

Решено:

export LC_ALL=C

... не знаю почему.

(работает для ASCII, по крайней мере, не имеет представления для UTF8)

Ответ 2

Как упоминалось ранее, LC_ALL=C sort делает трюк. Это просто потому, что разные языки имеют разные правила сортировки символов, которые часто выкладываются старшими лингвистами вместо экспертов CS. И эти правила, в случае вашей локали, похоже, говорят, что пробелы следует игнорировать при сортировке.

Префикс LC_ALL = C (или, когда LC_ALL не установлен, LC_COLLATE=C), вы явно объявляете агностическую сортировку языка (и, с LC_ALL, форматирование номера и прочее), что и есть то, что вы хотите в этом контексте, Если вы хотите сделать это по умолчанию, экспортируйте LC_COLLATE в свою среду.

По умолчанию выбирается таким образом, чтобы сохранить соответствие с "нормальными", реалистичными схемами сортировки (например, белые страницы), которые часто игнорируют пробелы.

Ответ 3

Использование языка C, т.е. сортировка только по байтовым значениям, не является хорошим решением на языках, где некоторые буквы находятся за пределами диапазона [A-Za-z]. Такие буквы представлены как несколько байтов в UTF-8, а затем порядок сортировки байтов не является тем, чего вы желаете. (Некоторые символы могут иметь два эквивалентных представления (предварительно составленные и декомпозированные)).

Тем не менее, обработка пространств является проблемой. Я попробовал следующее:

$ cat stest  
a b  
a c  
ab  
a d  

$ sort stest  
ab  
a b  
a c  
a d  

$ sort -k 1,1 stest  
a b  
a c  
a d  
ab  

Для моих нужд, -k 1,1 сделал трюк. Другое, но неуклюжее решение, которое я пробовал, состояло в том, чтобы сменить пробелы на некоторый вспомогательный символ, затем сортировать, а затем снова включить вспомогательные элементы в пробелы.

Ответ 4

Вы можете использовать программу env для временного изменения LC_COLLATE на время сортировки; например.

/usr/bin/env LC_COLLATE = POSIX/bin/sort file1 file2

Это немного громоздко в командной строке, но если вы используете его в script, он должен быть прозрачным.

Ответ 5

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

Большинство вариантов, которые я видел в Интернете, и SO, похоже, рекомендуют то, что я вижу здесь, устанавливая локаль глобально (overkill)

export LC_ALL=C

или поместите его в каждую отдельную команду, например, из gnu.org (утомительно)

$ echo abcdefghijklmnopqrstuvwxyz | LC_ALL=C /usr/xpg4/bin/tr 'a-z' 'A-Z' ABCDEFGHIJKLMNOPQRSTUVWXYZ

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

Мне почему-то пришлось установить LANG вместо LC_ALL, но все отдельные локали были установлены, что для меня функционально.

Вот тест, простой, как может быть

#!/bin/bash
# locale_checker.sh

#Check and set locale to LC_ALL to optimize character sort and search.
echo "locale was $LANG"
LANG=C
locale

и вывести + доказательство того, что оно является временным и может быть ограничено моим процессом script.

[email protected]:~/snippets$ ./locale_checker.sh
locale was en_US.UTF-8
LANG=C
LANGUAGE=en_US:en
LC_CTYPE="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_COLLATE="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_PAPER="C"
LC_NAME="C"
LC_ADDRESS="C"
LC_TELEPHONE="C"
LC_MEASUREMENT="C"
LC_IDENTIFICATION="C"
LC_ALL=
[email protected]:~/snippets$ locale
LANG=en_US.UTF-8
LANGUAGE=en_US:en
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

Там вы идете. Вы получаете оптимизированный языковой стандарт, не загромождая невиновную среду другого человека, а также избегайте скуки трубопровода, где бы вы ни думали, что это может помочь.

Ответ 6

Собственно для меня

$ cat txt
ab
a c
a a
$ sort txt
a a
a c
ab

Я буду держать пари между вашими a и c, у вас есть неразрывное пространство или простое пространство, или empspace или другое пространство с высоким кодированием!

ИЗМЕНИТЬ

Просто запустил его в Linux. Я должен был посмотреть на теги. Да, я получаю тот же результат, что и вы! Мой первый запуск был на Mac. Похож на разницу между GNU и BSD. Я буду исследовать далее.

ИЗМЕНИТЬ 2:

Linux использует сортировку по полю... все еще ищет, как ее подавить. Пробовал

sort -t, txt

надеясь обмануть GNU, думая, что вся строка была одним полем, но она по-прежнему использовала текущую локаль для сортировки.

ИЗМЕНИТЬ 3:

OP решила проблему, установив локаль на C с помощью

export LC_ALL=C

Похоже, что другого подхода нет. Команда sort будет использовать текущую локаль, и хотя она часто говорит, что c (или его псевдоним POSIX) является языковым стандартом по умолчанию, если у вас есть Linux, он, вероятно, был установлен для вас. Введите locale -a, чтобы просмотреть доступные локали. В моей системе:

$ locale -a
C
POSIX
en_AG
en_AU.utf8
en_BW.utf8
en_CA.utf8
en_DK.utf8
en_GB.utf8
en_HK.utf8
en_IE.utf8
en_IN
en_NG
en_NZ.utf8
en_PH.utf8
en_SG.utf8
en_US.utf8
en_ZA.utf8
en_ZW.utf8

Кажется, что установка языкового стандарта в C (или его псевдоним POSIX) является единственным способом разбить полевое поведение sort и рассматривать всю строку как одно поле. Это довольно странно ИМХО, что так оно и есть. Я бы подумал, что варианты -t или -k, или, возможно, какой-то новый вариант станут более разумным способом сделать это.

Кстати, похоже, этот вопрос был задан до SO: неожиданный результат из сортировки gnu.

Ответ 7

Странно, работает здесь (cygwin).

Попробуйте sort -d txt.