
Я хочу получить все строки, в которых есть слово 'search_string' + строка после него + строка, соответствующая 'mod' перед ним.
Я попробовал:
grep -n 'mod\|search_string' ip | grep --before 1 search_string> inter
grep -n --after 1 search_string ip >> inter
sort -t':' -k1,1n -u inter -o op
Есть ли способ лучше?
Файл:
mod start1
some lines
mod start2
other lines
mod start3
many other lines
search_string yada yada
hello
many other lines
search_string yada yada
bye
mod start4
search_string baba baba
this too
mod start5
Ожидаемый результат:
mod start3
search_string yada yada
hello
search_string yada yada
bye
mod start4
search_string baba baba
this too
решение1
awk '
$0 ~ /mod/ { md=$0 }
$0 ~ /search_string/ { if(md!="") { print md }; md="" ; print; getline; print }
'
Объяснение:
- Строка, содержащая ,
mod
сохраняется какmd
. - Строка, содержащая
search_string
триггеры, печатающие ранее сохраненную строкуmd
, саму строку и следующую строку. if(md!="")
иmd=""
существуют для того, чтобы убедиться, что вы не получите дублирующиеся строки, когда в одной строкеmod
находится несколько символов - ( в вашем примере).search_string
mod
mod start3
Примечание:
- Строка, содержащая
mod
и ,search_string
нарушит эту логику.
решение2
Ваш файл содержит символы "возврата каретки". В Unix их лучше удалить. Чтобы напечатать то, что печатает последовательность команд, которые вы разместили (с удаленными возвратами каретки), попробуйте:
awk '{gsub(/\r/,"")}
/mod/ { a = $0 }
/search_string/{ if(a!=""){print(a);a=""}
print;getline;print
}
' infile
Или в одной строке:
$ awk '{gsub(/\r/,"")}/mod/{a=$0}/search_string/{if(a!=""){print(a);a=""}print;getline;print}' infile
mod start3
search_string yada yada
hello
search_string yada yada
bye
mod start4
search_string baba baba
this too
Поскольку в (GNU) awk можно использовать многосимвольный разделитель записей, мы можем установить разделитель записей на mod
и вывести только записи, содержащие search_string
. Для восстановления исходной записи требуется printf.
Чтобы распечатать то, что вы разместили как «Ожидаемый вывод», попробуйте:
awk '/search_string/{printf("mod%s", $0)}' RS=mod infile
решение3
Если вы хотите это в скрипте Python:
# Read file into memory.
with open('myfile.txt') as f:
lines = [line.rstrip() for line in f]
# Loops through lines backwards, looking for string and optionally mod.
output_lines = list()
find_mod = False
for i, line in enumerate(lines[::-1]):
if 'search_string' in line:
output_lines.append(lines[::-1][i-1])
output_lines.append(lines[::-1][i])
find_mod = True
elif find_mod and 'mod' in line:
output_lines.append(lines[::-1][i])
find_mod=False
print("\n".join(output_lines[::-1]))