Как отсортировать блоки данных различной длины на поле в каждом блоке

У меня есть RDF-файл с блоками данных различного числа строк, обозначенных < и /> . Внутри каждого блока есть поле, обозначенное как name="some name" . Мне нужно отсортировать блоки по значению name без изменения порядка какой-либо из строк в каждом блоке. Кроме того, в каждом блоке есть поле с номером. Мне нужно изменить нумерацию этих полей от 1 до n в зависимости от отсортированной позиции каждого блока.

Вот пример из 3 блоков:

    

Число, на которое я ссылался, – это число, следующее за $CHROME в приведенном выше примере. Я старый ассемблер, COBOL, Fortran, программист на Basic, но я не собираюсь разбираться со скриптами или более новыми языками. Я мог бы, вероятно, сделать это в программе Basic, но я бы хотел решение Linux, если это возможно.

Я надеюсь, что есть какой-то символ – или, по крайней мере, некоторая строка – которая никогда не появится в вашем файле. Я предполагаю, что это верно для | , Для большей безопасности я буду использовать || ,

Запустите эту команду:

  sed -n -e H -e '/ ^ * \ /> * $ / {s /.*//;  Икс;  s /.* НС1: имя = "\ ([^"] * \) / \ 1 & /;  s / \ n / || / gp} ' your_file \
         |  Сортировать \
         |  нл -ба \
         |  sed -e 's / * \ ([0-9] * \) [^ |] * || \ (. * RDF: about = "rdf: # $ CHROME \) [0-9] * / \ 2 \ 1 / '-e' s / || / \ n / g ' 

Примечание: это (вероятно) требует наличия GNU sed.

обзор

  • Используйте sed чтобы преобразовать файл в формат, подходящий для сортировки (подробности ниже).
  • Сортировать вывод из sed .
  • Применить (предварительно) номера строк. Используйте любую команду, которая будет генерировать подходящие числа. Мне нравится nl -ba , но cat -n будет работать так же хорошо, и, возможно, есть другие варианты.
  • Используйте sed чтобы убрать номер строки с начала строки и вставить его после CHROME . Разберите данные обратно в исходный формат.

Подробности – Первая команда sed

Команда sort обрабатывает каждую строку как запись. Поэтому мы берем каждую (разделенную) запись из вашего входного файла и объединяем все строки, образуя одну длинную строку. Мы также копируем значение name в начало строки, чтобы избежать необходимости указывать ключ сортировки.

  • Используйте параметр -n чтобы отключить автоматическую печать. Линии будут напечатаны только тогда, когда мы скажем p .
  • Выполните H в каждой строке. Это добавляет текущую строку в область удержания. Логически, возможно, имеет смысл скопировать строку < в пространство удержания (с помощью команды h ), а затем добавить все последующие строки. Я произвольно выбрал этот подход.

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

  • Найдите строку, содержащую /> , необязательно с предшествующим и / или сопровождаемым пробелами. Когда мы находим это, мы знаем, что у нас есть полная запись в области удержания. Выполните следующие команды только в этих строках.
    • s/.*// очищает пространство шаблона (т. е. стирает строку /> ). Это на самом деле не выбрасывает какую-либо информацию; строка /> уже была добавлена ​​в область удержания (потому что каждая строка добавляется в область удержания).
    • x меняет пространство образца и пространство удержания. Это извлекает агрегированную (добавленную / объединенную) запись из пространства удержания в пространство образца. Из-за предыдущей ( s/.*// ) команды это очищает пространство удержания.
    • s/.*NS1:name="\([^"]*\)/\1&/ ищет поле имени и копирует его значение в начало записи. Это не удастся, если вы можете иметь имя с символами кавычек в нем.
    • s/\n/||/gp заменяет каждую новую строку в пространстве шаблонов на || , (Это шаг, который преобразует запись в одну строку.) Из-за p печатается запись.

Вывод первой команды sed при запуске в файле примера

 AAA Carolinas|| Adobe Forums|| Adorama|| 

Подробности - Вторая команда sed

  • s/ *\([0-9]*\)[^|]*||\(.* RDF:about="rdf:#$CHROME\)[0-9]*/\2\1/ прерывает линия на куски:

    • Ноль или более пробелов.
    • Номер строки (ноль или более цифр). Это становится группой \1 .
    • Вкладка после номера строки, значения name и || после этого.
    • Запись через RDF:about="rdf:#$CHROME . Это становится группой \2 .
    • Старый номер записи (ноль или более цифр).
    • Неявно, остальная часть записи.

    Затем он заменяет первые пять частей на RDF:about="rdf:#$CHROME и номер строки (номер новой записи). Поскольку остальная часть записи не была сопоставлена, команда не влияет на нее.

  • s/||/\n/g заменяет каждый || с новой строкой, восстановление (воссоздание) исходной многострочной структуры файла.

Очевидно, ...

… Чтобы отправить вывод в файл, добавьте > your_output_file в самом конце последней строки команды (т. > your_output_file конце второго sed ). Затем вы можете переместить ( mv ) your_output_file в исходный файл. Нет никакого смысла указывать параметр --output= (или -o ) для команды sort ; вывод из sort должен идти в команду, которая применяет номера строк. Если вы хотите захватить промежуточный файл, скажите так.