Группы строк в файле:
Types datadata
Term datadata
Vendor datadata
Feature datadata
Types datadata
Term datadata
Feature datadata
Types datadata
Feature datadata
Первая группа строк в порядке. Во второй группе мне нужно добавить строку для vendor
. Для третьей группы мне нужно добавить две строки для term
и vendor
. Я искал похожие вопросы, но не нашел правильного решения. Это заголовки для данных, которые следуют справа в той же строке, поэтому я не могу использовать простой поиск и замену.
Желаемый результат:
Types datadata
Term datadata
Vendor datadata
Feature datadata
Types datadata
Term datadata
;
Feature datadata
Types datadata
;
;
Feature datadata
Я создал файл script.awk
, содержащий этот код:
function print_key(key)
{
if (key in saved)
print saved[key]
else
print ";"
}
function process_data()
{
if (nsaved > 0)
{
print_key("Types")
print_key("Term")
print_key("Vendor")
print_key("Feature")
print ""
}
delete saved
nsaved = 0
}
NF > 0 { saved[$1] = $0; nsaved++ }
NF == 0 { process_data() }
END { process_data() }
Я запустил его на ваших примерных данных (содержащихся в файле с именем data
):
$ awk -f script.awk data
Types datadata
Term datadata
Vendor datadata
Feature datadata
Types datadata
Term datadata
;
Feature datadata
Types datadata
;
;
Feature datadata
$
Что делает скрипт:
key
. Если этот ключ присутствует в массиве saved
, он печатается; если нет, то точка с запятой печатается на отдельной строке."Types"
, "Term"
, "Vendor"
и "Feature"
, а затем пустую строку. Он также удаляет сохраненные данные, удаляя массив saved
и возвращая nsaved
к нулю.saved
и сохраняет всю строку для последующей печати.Хороший сценарий! FWIW У меня возник соблазн использовать function val(key) { if (key in saved) return saved[key]; else return ";" }
и print val("Types")
только для того, чтобы определение значения не было связано с выполнением каких-либо действий со значением (например, его печатью), и поэтому только 1 функция выполняет всю печать. Но нбд в любом случае.
Это разумное изменение, @EdMorton — я мог бы даже внести его, если бы планировал серьезно использовать сценарий.
Я бы сделал это следующим образом, пусть file.txt
content будет:
Types datadata
Term datadata
Vendor datadata
Feature datadata
Types datadata
Term datadata
Feature datadata
Types datadata
Feature datadata
затем
awk 'BEGIN{arr["Types"]=arr["Term"]=arr["Vendor"]=arr["Feature"] = ";"}
(NF>=1){arr[$1]=$0}
(NF<1){print arr["Types"];print arr["Term"];print arr["Vendor"];print arr["Feature"];print $0;
arr["Types"]=arr["Term"]=arr["Vendor"]=arr["Feature"] = ";"}
END{print arr["Types"];print arr["Term"];print arr["Vendor"];print arr["Feature"]}' file.txt
выход
Types datadata
Term datadata
Vendor datadata
Feature datadata
Types datadata
Term datadata
;
Feature datadata
Types datadata
;
;
Feature datadata
Объяснение: В BEGIN
я создаю arr
с Types
, Term
, Vendor
, Feature
всеми ;
. Для каждой строки с данными я устанавливаю соответствующее значение arr
для этой строки. Для каждой строки без данных я печатаю содержимое arr
в нужном порядке, эту строку без данных и снова устанавливаю все в arr
на ;
. В END
я печатаю arr
так же, как и для строки без данных - это требуется тогда и только тогда, когда последняя строка ваших данных не пуста.
(проверено в gawk 4.2.1)
Это все очень хорошие варианты! Я работаю со всеми тремя, чтобы увидеть, как они работают и работают в рамках моего более длинного сценария. Я выберу один в качестве ответа, но можно использовать любую из этих трех версий.
$ cat tst.awk
{ tag2val[$1] = $0 }
!NF { prt() }
END { prt() }
function prt( n,i,tag,tags) {
n = split("Types Term Vendor Feature",tags)
for (i=1; i<=n; i++) {
tag = tags[i]
print (tag in tag2val ? tag2val[tag] : ";")
}
print ""
delete tag2val
}
$ awk -f tst.awk file
Types datadata
Term datadata
Vendor datadata
Feature datadata
Types datadata
Term datadata
;
Feature datadata
Types datadata
;
;
Feature datadata
Пожалуйста, добавьте свои усилия в виде кода, который настоятельно рекомендуется на SO.