Извлечь и переставить из файла

Извлечь и переставить из файла

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

ссылка:cve,2017-8962
сид:45885
ссылка:cve,2016-10033
ссылка:cve,2016-10034
ссылка:cve,2016-10045
ссылка:cve,2016-10074
сид:45917
ссылка:cve,2017-8046
сид:45976
ссылка:cve,2018-6577
ссылка:cve,2018-6578
сид:46062

и файл ниже - это новый файл, содержащий требуемый вывод

ссылка:cve,2017-8962
сид:45885
ссылка:cve,2016-10033
сид:45917
ссылка:cve,2016-10034
сид:45917
ссылка:cve,2016-10045
сид:45917
ссылка:cve,2016-10074
сид:45917
ссылка:cve,2017-8046
сид:45976
ссылка:cve,2018-6577
сид:46062
ссылка:cve,2018-6578
сид:46062
.

Объяснение: для примера sid:45917 есть четыре ссылки, это (reference:cve,2016-10033 reference:cve,2016-10034 reference:cve,2016-10045 reference:cve,2016-10074), нам нужно разделить каждую ссылку и добавить sid один под другим (примечание: за sid всегда следует ссылка), например, здесь есть повторяющиеся блоки, поэтому, если ссылок несколько, нам нужно добавить их в порядке добавления новых файлов.

решение1

Как вы, кажется, используетеотложенный sid:s (множественные, references:за которыми следуют их единичные sids:=> пары references:и sid:), два решения.


Решение 1: реверс

Просто используйте tacкоманду (этокотв обратном порядке) для замены входа и выхода:tac input | awk | tac > output

Для части awk просто продублируйте sid:s:

gawk '/^sid:/{sid=$0};/^reference:/{print sid "\n" $0}'

Решение 2: массив

Сохраняйте reference:символы s в массиве по мере их поступления, а затем выдавайте их обратно при обнаружении соответствующих символов.sid:

gawk 'BEGIN{r=0};/^reference:/{ref[r++]=$0};/^sid:/{for(n=0;n<r;n++){print ref[n] "\n" $0};r=0}' /tmp/test.txt

/^reference:/{ref[r++]=$0}: для каждой строки, которая начинается с ref... сохранить строку в массиве и переместить указатель «r» на следующий элемент.

/^sid:/{for(n=0;n<r;n++){print ref[n] "\n" $0};r=0}: всякий раз, когда строка начинается с sid, пройти по всему массиву до указателя r (for...) и для каждого элемента вывести сохраненную ссылку и текущую строку (=sid), затем сбросить r обратно в начало, чтобы начать снова со следующих ссылок.

решение2

awk 'BEGIN { i=0; }
/^reference:/ { ref[i++] = $0; }
/^sid:/ { for(j=0; j<i; j++) { print ref[j]; print; } i=0; }' inputfile > outputfile

Объяснение:

  • BEGIN { i=0; }Инициализируйте переменную, чтобы убедиться, что она интерпретируется как числовое значение 0, а не как пустая строка "".
  • /^reference:/ { ref[i++] = $0; }Для каждой строки, которая начинается с reference:( ^является привязкой к началу строки), скопируйте всю строку $0в элемент массива ref[i]и увеличьте индексi++
  • /^sid:/ { ... }для каждой строки, которая начинается с sid:...
  • for(j=0; j<i; j++) { ... }Поскольку iуказывает на элемент массива после последнего использованного, перебирает все элементы массива, в которые была сделана запись, используя индекс j,
  • print ref[j];распечатать содержимое элемента массива, т.е. сохраненную reference:строку
  • print;распечатать текущую строку, т.е. sid:строку
  • i=0;сбросить индекс массива на начало для следующей группы reference:строк

Сценарий основан на следующих предположениях:

  • Входные данные состоят из серии блоков, где каждый блок содержит
    • последовательность из одной или нескольких reference:строк, за которыми следует
    • одна sid:строка
  • Последняя строка должна быть sid:строкой.
  • Несовпадающие строки будут игнорироваться.

В исходном вопросе я предположил неправильное направление преобразования. Второй скрипт преобразует в противоположном направлении:

awk 'BEGIN { oldsid=""; ref=""; }
/^reference:/ { ref=$0; }
/^sid:/ { if(oldsid != $0) { if(oldsid != "") print oldsid; } if(ref!="")print ref; oldsid=$0; }
END { if (oldsid != "") print oldsid; }' inputfile > outputfile

Объяснение:

  • BEGIN { oldsid=""; ref=""; }Инициализируйте переменные для ясности, это не обязательно.
  • /^reference:/ { ref=$0; }Для каждой строки, которая начинается с , reference:сохраните строку $0в переменной ref, но пока не выводите ее на печать.
  • /^sid:/ { ... }Для каждой строки, которая начинается с sid:...
  • if(oldsid != $0) { if(oldsid != "") print oldsid; }Если sid:строка сейчас изменилась, последняя reference:строка, сохраненная в refпринадлежит новому sid:, поэтому мы пока ее не печатаем. Если oldsidне пусто, мы можем распечатать ее сейчас, так как предыдущий блок reference:строк с тем же самым sid:завершен. oldsidбудет пустым, когда мы найдем первый sid:.
  • if(ref!="")print ref;Если у нас есть сохраненный reference:, вывести его сейчас. (Либо мы только что закрыли предыдущий блок соответствующей sid:строкой, либо теперь знаем, что текущий reference:имеет то же самое sid:, что и предыдущий.) Проверка на пустую строку на самом деле не нужна, поскольку я предполагаю, что каждой sid:строке предшествует reference:строка.
  • oldsid=$0;сохранить текущую sid:строку для сравнения, когда получим следующую. Текущая строка еще не напечатана.
  • END { if (oldsid != "") print oldsid; }В конце выведите последнюю сохраненную sid:строку, если таковая имеется. (Если входной файл пуст, пустая строка здесь не выводится.)

Этот сценарий основан на следующих предположениях:

  • за каждым reference:следуетsid:
  • все пары reference:и sid:с той же sid:строкой следуют друг за другом

Связанный контент