Изменить ЗАПРОС _КОМАНДА на:
PROMPT_COMMAND='if [ $? -eq 0 ]; then counter=$((counter+1)); else counter=0; fi'
Используйте одинарные -кавычки, чтобы предотвратить преждевременное расширение $?
, и используйте прямое присвоение для увеличенного значения counter
.
Если вам также нужно решение Sed, это некрасиво, но должно работать.
sed -n '
/^A/{
N
/\nB/!D
N
/\nC/!{
s/\n//
D
}
p
}
' file
-n
указывает sed не печатать ничего, пока не будет достигнута команда p
.
Если вы понимаете первый блок, вы можете понять и остальные:
/^A/
Если пространство шаблонов начинается с A, N
Добавить следующую строку в пространство шаблона. /\nB/!D
Если в пространстве шаблонов нет новой строки, за которой следует B, удалите все до первой новой строки и начните заново с результирующим пространством шаблонов и без чтения каких-либо входных данных. Один вкладыш:sed -n '/^A/{N;/\nB/!D;N;/\nC/!{s/\n//;D};p}' file
Следующая awk
программа должна работать:
awk 's==2{if (/^C/) {s=0; p=p ORS $0; print p} else {s=0}}\
s==1{if (/^B/) {s=2; p=p ORS $0} else {s=0}}\
s==0{if (/^A/) {s=1; p=$0}}' input.txt
Это сохранит внутренний флаг «статуса» s
, чтобы увидеть, в какой точке последовательности мы находимся (0 :начало не найдено, 1:A
найдено, 2:A
и B
находится в последовательности )и накапливает текст в буфере p
.
A
и B
были найдены, а текущая строка начинается с C
, мы добавляем текущую строку в буфер и печатаем ее. Состояние сбрасывается на0
A
найдено, и текущая строка начинается с B
, мы добавляем текущую строку в буфер и устанавливаем статус2
(= A
и B
найдено)A
, мы добавляем это в буфер и устанавливаем статус в 1
. вы можете настроить конечный автомат в sed для перехода к следующему состоянию, только если предыдущее состояние приведет вас к A -> B -> C
В противном случае отрубите голову и перезапустите.
$ sed -e '$d;/\n/d
/^A/N;/\nB/!D
$!N;/\nC/!D
' file
A1
B1
C1
A4
B4
C4
если у вас есть gnu grep, скомпилированный с опцией PCRE, то следующий код grep Есть другой способ.
$ grep -zoP '(?m)^A.*\nB.*\nC.*\n' file | tr -d '\0'
Другое решение сawk
:
awk 'p2~/^A/ && p1~/^B/ && /^C/{print p2 RS p1 RS $0} {p2=p1; p1=$0}'
С perl
и выделением всего ввода как одной строки:
perl -0777 -ne 'print /^A.*\nB.*\nC.*\n/mg'
С ripgrep , который поддерживает удобную опцию многострочного сопоставления-U
rg -oUN '^A.*\nB.*\nC.*'
Здесь опция -o
получает только совпадающую часть, а опция -N
предназначена для предотвращения номеров строк в выводе
Это основано на многострочном пространстве шаблонов -и отбрасывает самую верхнюю -строку, как только совпадение не найдено, и затем поиск начинается заново. Линии добавляются после каждого матча. Группа считается полностью подобранной, когда все части совпадают по очереди :
.sed '/^A/!D; /\n/!N; /\nB/!D; N; /\nC/!D'
Решение можно обобщить, чтобы оно соответствовало произвольному количеству строк, и немного больше внимания уделять изоляции поисковых терминов. Приведенный ниже скрипт будет соответствовать группе из 4 -строк (, например. A|B|A|B ), просто замените каждую букву «X» последовательной строкой:
sed '
# If X does not begin pattern space, delete first line,
# return to script start, read a line if none remain
/^X/!D
# Append next line if pattern space holds 1 line
/\n/!N
# If X does not begin line 2+ of pattern space, delete first line,
# return to script start, read a line if none remain
/\nX/!D
# Append next line if pattern space holds < 3 lines
/\n.*\n/!N
# If X does not begin line 3+ of pattern space, delete first line,
# return to script start, read a line if none remain
/\n.*\nX/!D
# Append next line if pattern space holds < 4 lines
/\n.*\n.*\n/!N
# If X does not begin line 4+ of pattern space, delete first line,
# return to script start, read a line if none remain
/\n.*\n.*\nX/!D
# After here, output pattern space then discard and start again
'