У меня есть куча файлов:

adenine-N1_B+1,70_A+0,00.pdb
adenine-N1_B+1,70_A-10,00.pdb
adenine-N1_B+1,70_A+10,00.pdb
adenine-N1_B+1,70_A-15,00.pdb
adenine-N1_B+1,70_A+15,00.pdb
adenine-N1_B+1,70_A-20,00.pdb
adenine-N1_B+1,70_A+20,00.pdb
adenine-N1_B+1,70_A-25,00.pdb
adenine-N1_B+1,70_A+25,00.pdb
adenine-N1_B+1,70_A-30,00.pdb
adenine-N1_B+1,70_A+30,00.pdb
adenine-N1_B+1,70_A-5,00.pdb
adenine-N1_B+1,70_A+5,00.pdb

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

adenine-N1_B+1,70_A-30,00.pdb
adenine-N1_B+1,70_A-25,00.pdb
adenine-N1_B+1,70_A-20,00.pdb
adenine-N1_B+1,70_A-15,00.pdb
adenine-N1_B+1,70_A-10,00.pdb
adenine-N1_B+1,70_A-5,00.pdb
adenine-N1_B+1,70_A+0,00.pdb
adenine-N1_B+1,70_A+5,00.pdb
adenine-N1_B+1,70_A+10,00.pdb
adenine-N1_B+1,70_A+15,00.pdb
adenine-N1_B+1,70_A+20,00.pdb
adenine-N1_B+1,70_A+25,00.pdb
adenine-N1_B+1,70_A+30,00.pdb

Есть команда сортировки, чтобы сделать это? Пока у меня есть следующее:

for i in $(ls *.pdb | sort -V); do echo $i; done

1 ответ1

0

ТЛ; др

ls *.pdb | sort -k 1.20g

(Да, я знаю это и многое другое; см. Раздел «Подводные камни» ниже).


Логика сортировки

Обычная числовая сортировка (sort -g) - это та, которую вы хотите, но вы должны указать, где начинаются числа.

Ваши примеры имеют вид:

adenine-N1_B+1,70_A-15,00.pdb
                   ^ the number starts here: character 20, always

Пробелов нет, поэтому обычная sort рассматривает все имя файла как одно поле. Вам нужна общая числовая сортировка, которая работает с 20-го символа 1-го поля:

sort -k 1.20g

Вы можете ввести более сложную логику для этого. Например, если бы одна из записей была bogonine-X3_B+1,00_A-12,00.pdb , было бы весьма разумно разложить записи следующим образом:

foo_bar_A+00,00.pdb
   ^   ^ field separators
^ first field starts here
        ^ third field starts here
         ^ the number starts here: field 3, character 2

и отсортировать (например) по первому полю, затем по этим числам, например так:

sort -t '_' -k 1,1 -k 3.2g

(Сравните этот ответ).


место действия

Локаль, указанная средой, влияет на порядок сортировки. Можно на всякий случай посоветовать установить LC_ALL=C Это может или не может быть тем, что вы хотите, в зависимости от того, хотите ли вы рассматривать последнюю запятую (,) как десятичный разделитель или нет (ну, у вас есть ,00 в каждой записи, так что это не должно иметь большого значения; но это имеет значение в целом).

Если вам нужно изменить локаль только для одного конкретного вызова sort , это так:

LC_ALL=C sort …

Подводные камни в различных подходах

Вот что вы пробовали:

for i in $(ls *.pdb | sort -V); do echo $i; done

Команда слишком сложна, внутренняя часть выполняет в основном ту же работу:

ls *.pdb | sort -V

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

for i in *.pdb; do echo "$i"; done | sort …

Проблема с ls *.pdb том, что вы можете получить argument list too long ошибку в списке аргументов (ну, не в вашем примере, но опять же: в общем). Синтаксис for i in *.pdb; … неуязвим.

Названия вашего примера, похоже, безопасны для использования с echo (см. Общую проблему с echo). Они не содержат специальных символов, поэтому вам не нужно find … -print0 или sort -z … и т.д.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .