Как мне сначала сделать символы подчеркивания ls sort?

20

Мне нравится иметь возможность присваивать имена файлам и каталогам префикс подчеркивания, если я хочу отделить их от других файлов и каталогов на том же уровне. Например, в Windows и Mac префикс файла с подчеркиванием сортирует его по началу, перед файлами, начинающимися с буквенно-цифрового символа.

Я обнаружил, что поиск в Google связан с LC_COLLATE и моей текущей локалью (en_US). Это хорошо, хотя я действительно не понимаю, почему en_US не сортирует, как ожидалось.

Основываясь на настройке локали демонстрационного сайта ICU Collate в en_US_POSIX, безусловно, имеет искомый порядок сортировки (вы должны отредактировать пример данных и добавить несколько подчеркиваний, чтобы проверить их). Но я не понимаю, как применить это в моей оболочке Linux.

В идеале я хотел бы иметь возможность настроить что-то в моей конфигурации bash, чтобы ls всегда сначала сортировал подчеркивания. Как бы я поступил так?

Том Оже
источник
Я не могу воспроизвести с использованием ICU Collate со значениями по умолчанию или en_US_POSIX.txt через «Выбор правил для локали». Можете ли вы объяснить настройки, которые вы использовали?
Микель
Аналогичный вопрос askubuntu.com/questions/47702/…
Микель
@Mikel, используя приведенную выше ссылку, добавьте несколько подчеркиваний к тестовым данным и затем отправьте их, чтобы увидеть результаты сортировки.
Том Оже
Это именно то, что я сделал, и строки, начинающиеся с подчеркивания, сортируются в середине, а не в начале, как будто подчеркивания не было.
Микель
1
Смежный вопрос, который касается фактического изменения определения порядка сортировки, - unix.stackexchange.com/questions/421908 .
JdeBP

Ответы:

5

Если вы не можете lsотсортировать, как хотите, попробуйте расширение оболочки.

Вы можете использовать шаблоны имен файлов для запуска lsсо списком файлов, которые оболочка уже отсортировала, минуя используемый метод ls.

ls -lf _* [!_]*

Если у вас есть файлы

_a a _b b _c c

это как бег

ls -lf _a _b _c a b c

Объяснение:

_* шаблон оболочки, соответствующий любому имени файла, начинающемуся с подчеркивания, расширенный в алфавитном порядке.

[!_]*соответствует любому имени файла, не начинающемуся с подчеркивания, расширенному в алфавитном порядке.

-fговорит , lsчтобы не сортировать, так как оболочка уже сделал.

Больше информации: расширение имени файла bash

Если в текущем каталоге есть каталоги, вы можете выполнить команду, подобную этой, чтобы избежать ls перечисления файлов в каталогах:

ls -lfd _* [!_]*
Mikel
источник
7
Кстати, DOS / Windows / OSX на самом деле не ставят подчеркивания перед чем-либо еще: они сортируют без учета регистра с подчеркиванием, поставленным перед буквами, но некоторые другие знаки препинания идут до или после подчеркивания. Использование _для того, чтобы файлы появлялись первыми, является хаком для конкретной ОС; и Unix-версия этого хака заключается в том, чтобы начинать имя файла с заглавной буквы: соглашение Unix по умолчанию заключается в использовании только строчных букв в именах файлов.
Жиль "ТАК ... перестать быть злым"
4
Или нули; например 00README.
mattdm
1
@Gilles +1 за лучшую практику Unix по использованию заглавных букв для важных файлов, чтобы сделать их первыми. В конце концов, если это соглашение, вероятно, лучше просто принять его, а не пытаться заставить Unix вести себя так, как это делают другие ОС, чтобы я мог использовать соглашения, разработанные для Mac или Windows. Спасибо за отличный совет.
Том Оже
1
@TomAuger -fговорит lsне делать свою собственную сортировку, поэтому она показывает свои аргументы в порядке , они прошли. Результат каждого оболочки подстановочного расширения _*и [!_]*является лексикографически отсортированного списка.
Жиль "ТАК - перестать быть злым"
1
@TomAuger Аргументы to lsсортируются (в две группы: те, которые начинаются с _, затем другие), когда они генерируются оболочкой. Беги, echo ls -lf _* [!_]*чтобы увидеть, что происходит. -fФлаг говорит lsне делать какую - либо сортировки.
Жиль "ТАК ... перестать быть злым"
16

Если вам не нужно смешивать строчные и прописные буквы, установите для вашей локали значение C, которое принимает символы в их числовом порядке. _падает между прописными и строчными буквами.

$ LC_COLLATE=C ls    
BAR  FOO  _score  _under  hello  world
$ LC_COLLATE=en_US ls                    
BAR  FOO  hello  _score  _under  world

Настройки локали LC_MESSAGES(язык сообщений об ошибках), LC_CTYPE(наборы символов) и LC_TIME(формат даты и времени) очень полезны. LC_COLLATEи, LC_NUMERICкак правило, больше проблем, чем они стоят, я не рекомендую устанавливать их. Правильная лексикографическая сортировка сложнее, чем LC_COLLATEпредполагается, и может вызывать все виды странного поведения при использовании диапазонов символов в регулярных выражениях. LC_NUMERICв основном косметический, за исключением случаев, когда что-то идет ужасно неправильно, потому что какая-то программа выдает число с десятичным разделителем, кроме ..

Жиль "ТАК - перестать быть злым
источник
+1 Очень интересно. Итак, используя эту форму, вы временно устанавливаете переменную окружения LC_COLLATE только для этого одного экземпляра ls? Это правильно?
Том Оже
1
Есть ли способ сделать подчеркивание до заглавных букв?
Том Оже
1
@TomAuger Да, VAR=value cmdнаборы VARдля valueтолько в среде cmdи не затрагивает значение (или отсутствие значения) в оболочке , где вы запустите его. Чтобы подчеркивание отображалось перед заглавными буквами, вам необходимо определить свои собственные настройки локали. Это возможно, но неудобно в использовании, потому что, по крайней мере, в Linux стандартная библиотека ищет только определения локали /usr/lib/locale- в ней нет ~/.localeпеременной среды, в которую вы можете поместить свой en_tomпараметр.
Жиль "ТАК ... перестать быть злым"
@TomAuger Если речь идет только о lsкоманде, следуйте совету Микеля .
Жиль "ТАК ... перестать быть злым"
2

К сожалению, Linux использует glibc для информации о локали, а не ICU, поэтому нет никакого способа напрямую применить это к Linux, не затрачивая много усилий, ни перенеся ICU в glibc, ни добавив информацию о локали в glibc.

Игнасио Васкес-Абрамс
источник
-4

Добавление -fпереключателя (без сортировки) заставило меня показать это таким образом.

man ls

[root@dusknoir ~/java/test]# ls -fl
total 0
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 _1
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 _2
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 _3
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 1
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 2
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 3
Тим
источник
6
Только потому, что именно так они хранятся в файловой системе.
Игнасио Васкес-Абрамс
3
Извините, но этот ответ совершенно неверный. Тест: touch 3 1 _1 _3 2 _2 && ls -flвыходы2 . 1 3 _2 _3 .. _1
Марко