Сортировать раздел файла

8

Можно ли отсортировать две строки в большом файле?

Например, текущий файл имеет вид:

    0cf  Front Brake
    0d0  Rear Brake
    0ce  Handle Bars
HUT 03  VR Controls
    009  Vest
    001  Belt
    002  Body Suit
    020  Stereo Enable
    003  Flexor
    007  Hand Tracker
    004  Glove
    006  Head Mounted Display
    008  Oculometer
    00a  Animatronic Device
    000  Unidentified
    021  Display Enable
    005  Head Tracker
HUT 04  Sport Controls
    000  Unidentified
    002  Golf Club
    001  Baseball Bat

И желаемый результат такой:

    0ce  Handle Bars
    0cf  Front Brake
    0d0  Rear Brake
HUT 03  VR Controls
    000  Unidentified
    001  Belt
    002  Body Suit
    003  Flexor
    004  Glove
    005  Head Tracker
    006  Head Mounted Display
    007  Hand Tracker
    008  Oculometer
    009  Vest
    00a  Animatronic Device
    020  Stereo Enable
    021  Display Enable
HUT 04  Sport Controls
    000  Unidentified
    001  Baseball Bat
    002  Golf Club

Здесь раздел HUT 03 VR Controls и HUT 04 Sports Control отсортирован.

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

SHW
источник
Являются ли секции номерами с фиксированными строками или определены шаблонами?
Sparhawk
Заголовки разделов начинаются с первого символа строки, а их содержимое начинается с пробела / табуляции. Разделы не на фиксированные номера.
SHW
Вы хотите отсортировать только один раздел (по названию вопроса и текста) или каждый раздел?
Кусалананда
@Kusalananda Я согласен, что вопрос в этом вопросе неоднозначен; однако пример вывода показывает все отсортированные секции (или их части).
Стивен Китт
Я бы не сказал, что «Хижина» использует шестнадцатеричные символы.
Jlliagre

Ответы:

7

В Python:

#!/usr/bin/python3

with open("file.txt", "r") as ins:
    lines = []
    for line in ins:
        if line.startswith((" ", "\t")):
            lines.append(line)
        else:
            lines.sort()
            print(*lines, end = "", sep = "")
            print(line, end = "")
            lines = []
    lines.sort()
    print(*lines, end = "", sep = "")

Это сортирует все разделы (отдельно), а не только те, которые находятся между двумя конкретными строками.

Стивен Китт
источник
Superb! Это мастерство.
SHW
6

Для удовольствия, вот способ сортировки одного раздела с помощью ex:

ex file <<%
/HUT
+1,/HUT/-1!sort
w file.sorted
q
%
jlliagre
источник
6
$ awk 'BEGIN { OFS="\t"; s=0 } /^[^[:blank:]]/ { print ++s "\b", $0; next } { print s, $0 }' file | sort -n | cut -f 2-
    0ce  Handle Bars
    0cf  Front Brake
    0d0  Rear Brake
HUT 03  VR Controls
    000  Unidentified
    001  Belt
    002  Body Suit
    003  Flexor
    004  Glove
    005  Head Tracker
    006  Head Mounted Display
    007  Hand Tracker
    008  Oculometer
    009  Vest
    00a  Animatronic Device
    020  Stereo Enable
    021  Display Enable
HUT 04  Sport Controls
    000  Unidentified
    001  Baseball Bat
    002  Golf Club

Используется awkдля добавления числа (и разделителя табуляции) перед каждой строкой, соответствующей разделу, в котором находится эта строка. Для заголовков разделов мы добавляем число, за которым следует символ возврата на одну позицию (только потому, что возврат на заднюю панель сортируется перед вкладками). Затем мы просто сортируем полученные данные по этим числам, а затем удаляем их и добавляем разделители табуляции.

Заголовки разделов определяются путем поиска непустых символов в начале строки.

Кусалананда
источник
1
Ницца! Мне особенно нравится трюк с реверсом.
Стивен Китт
1
При таком подходе вы также можете использовать номер раздела (после HUTполя) в качестве префикса, чтобы сортировать разделы тоже.
Стивен Китт
3

Вы можете получить awkи sortсотрудничать, чтобы сделать работу.

awk '
    /^[[:blank:]]/{print | "sort"; next}
    {close("sort"); print}; 
    END{close("sort")}
' file
  • Передайте каждую строку содержимого в sort
  • Вызов closeна sortкогда часть маркера встречается; это приводит sortк сбросу его вывода на стандартный вывод и выхода
  • Распечатать маркер раздела
  • Новый экземпляр sortвступает во владение для строк содержимого после маркера раздела
  • Вызов closeна sortконце , чтобы заботиться о заднем содержании
Iruvar
источник
1

Для таких задач мне часто бывает сложно написать сценарий. Если это нужно сделать только один раз и, возможно, для нескольких файлов, это можно сделать довольно просто, используя макрос, если вы откроете файл vimи наберете:

  • GoFAKE SECTION<ESC>: добавьте поддельный раздел в конце и убедитесь, что он находится в начале строки (вы можете включить cindentили autoindentвключить). Это необходимо и для сортировки последнего раздела.
  • gg: назад перейти к началу файла, затем файл начинается с раздела перейти вниз на одну строку с j
  • qq: начать запись макроса для регистрации q
  • v: начать выбор
  • /^\S\+<Enter>: поиск начала следующего раздела
  • k: вверх на одну строку
  • :!sort<Enter: сортировать раздел
  • nj: перейти к первому элементу следующего раздела
  • q: остановить запись макроса
  • @q: повторить макрос
  • 100@@: повторить макрос несколько раз (пока не останется ни одного раздела)
  • dd: удалить последнюю строку файла (the FAKE SECTION)

Вы можете :set lazyredrawускорить выполнение макроса.

MarcDefiant
источник