Иногда при выполнении через сетевое соединение (в частности, при изменении разрешений, например, с использованием sudo
) информация о размере терминала не распространяется на удаленную машину. Когда это происходит, конечно, некоторые программы не понимают, когда форматировать вывод, переносить строки и т. Д.
Обычно вы можете использовать программу resize
, чтобы запросить у терминала его ширину, и исправить это . Вы бы запустили это на удаленном компьютере, и он отправил бы escape-символы, чтобы запросить у терминала его размер, а затем он обновил бы представление удаленной машины о фактическом размере.
Я не думаю, что это выполнимо с grep
, но это возможно с AWK:
#! /usr/bin/awk -f
/FOO/ {
matched = 1
if (notfirst) print ""
notfirst = 1
}
/^$/ {
matched = 0
}
matched
С подсчетом совпадений:
#! /usr/bin/awk -f
/FOO/ {
matched = 1
if (matches) print ""
printf "Match %d\n", ++matches
}
/^$/ {
matched = 0
}
matched
В обоих случаях первые два блока определяют, следует ли копировать текущую запись на выход. Когда текущая запись соответствует «FOO», первый блок устанавливает matched
в 1,при необходимости выводит пустую запись (для отделения предстоящего вывода от предыдущего совпадения ); во втором варианте также увеличивает счетчик matches
и выводит заголовок. Когда текущая запись пуста, второй блок устанавливает matched
в 0. Условие одиночества matched
печатает текущую запись, если matched
равно 1.
Я включил решение pcregrep
и решение python
.
Если у вас установлено pcregrep
, вы можете использовать многострочный шаблон, такой как ^.*FOO.*$\n?(^.*\S.*$\n?)*
, например.:
pcregrep -M '^.*FOO.*$\n?(^.*\S.*$\n?)*' test.txt
Подвыражение ^.*FOO.*$\n?
будет соответствовать любой строке, содержащей строку FOO
, а подвыражение (^.*\S.*$\n?)*
будет соответствовать любому количеству последующих строк, содержащих не -пробельный символ.
Вот скрипт Python, который должен делать то, что вы хотите:
#!/usr/bin/env python3
# -*- encoding: utf8 -*-
"""grep_follow.py
Search a text file for a pattern,
and output that pattern and the
non-empty lines which immediately follow it.
"""
import re
import sys
# Get the search pattern and the input file as command-line arguments
pattern = sys.argv[1]
input_file = sys.argv[2]
# Set a flag to determine whether or not to output the current line
print_flag = False
with open(input_file, "r") as _input_file:
# Iterate over the lines of the input file
for line in _input_file:
# Remove trailing whitespace
line = line.rstrip()
# If the line is empty, stop producing output
if not line.strip():
print_flag = False
# If the line matches the search pattern, start producing output
elif re.search(pattern, line):
print_flag = True
# If the print flag is set then output the line
if print_flag:
print(line)
Вы бы запустили это так:
$ python grep_follow.py FOO test.txt
this line contains FOO
this line is not blank
This line also contains FOO
This line contains FOO too
Not blank
Also not blank
FOO!
Yet more random text
FOO!
Использование awk
вместоgrep
:
awk '/FOO/ { if (matching) printf("\n"); matching = 1 }
/^$/ { if (matching) printf("\n"); matching = 0 }
matching' file
Версия, которая перечисляет совпадения:
awk 'function flush_print_maybe() {
if (matching) printf("Match %d\n%s\n\n", ++n, buf)
buf = ""
}
/FOO/ { flush_print_maybe(); matching = 1 }
/^$/ { flush_print_maybe(); matching = 0 }
matching { buf = (buf == "" ? $0 : buf ORS $0) }
END { flush_print_maybe() }' file
Обе awk
программы используют очень простой «конечный автомат», чтобы определить, соответствует ли он в данный момент или нет. Совпадение шаблона FOO
приведет к переходу в состояние matching
, а совпадение шаблона^$
(с пустой строкой )приведет к переходу в состояние, отличное от -matching
.
Вывод пустых строк между совпадающими наборами данных происходит при переходах состояний изmatching
(либо в matching
, либо в не-matching
).
Первая программа печатает любую строку в состоянии matching
.
Вторая программа собирает строки в переменной buf
, когда находится в состоянии matching
. Он сбрасывает (очищает )это после возможной печати (в зависимости от состояния )вместе с меткой Match N
при переходах между состояниями (, когда первая программа выводит пустую строку ).
Вывод этой последней программы на примере данных:
Match 1
this line contains FOO
this line is not blank
Match 2
This line also contains FOO
Match 3
This line contains FOO too
Not blank
Also not blank
Match 4
FOO!
Yet more random text
Match 5
FOO!
sed -ne '/FOO/{x;P;x};/FOO/,/^$/p' testfile
Каждый блок не -пустых строк в выходных данных представляет собой один фрагмент совпадающих данных из входных данных. Количество новых строк варьируется.
Это
-n
);тогда /FOO/{x;P;x}
-использует пустое место хранения ); /FOO/
)и заканчивая пустыми строками(/^$/
); и, наконец, p
). this line contains FOO
this line is not blank
This line also contains FOO
This line contains FOO too
Not blank
Also not blank
FOO!
Yet more random text
FOO!
awk '/FOO/{print "===match " ++i "==="} /FOO/,/^$/' file
===match 1===
this line contains FOO
this line is not blank
===match 2===
This line also contains FOO
===match 3===
This line contains FOO too
Not blank
Also not blank
===match 4===
FOO!
Yet more random text
===match 5===
FOO!
Аналогичный вариант, в котором FOO
можно было легко заменить на что-то другое:
awk -vpat=FOO '$0~pat{print "===match " ++i "==="} $0~pat,/^$/' file
Опускание завершающей пустой строки в печати по умолчанию оставляется читателю в качестве упражнения;-)
Вот один -вкладыш, который может не совсем соответствовать критериям, но подходит достаточно близко для большинства целей.
gawk '/FOO/{p=1} {if(p) print} /^$/{p=0}' infile.txt
Первое правило устанавливает p=1
, если видит FOO. Второе правило печатает текущую строку, если p не равно нулю. Третье правило устанавливает p=0
, если уже напечатанная строка ()пуста. Поменяйте местами второе и третье правила, если вы не хотите, чтобы выводился пустой разделитель строки.
Это вариант, который нумерует и разделяет совпадения, если есть несколько экземпляров FOO, не разделенных пустыми строками
gawk '/FOO/{p=1; n++; print "\n" n} /^$/{p=0} //{if (p) print $0 }' infile.txt