
У меня есть файл, из которого я хочу извлечь и переупорядочить определенные данные. Старый файл содержит необработанные данные. Этот файл является входным.
ссылка: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:
строкой следуют друг за другом