У меня есть миллионы записей в файле, которые выглядят так
echo "NEW Cell"
grep "2553,24" out.2A25.20090308.64436.7.HDF.txt.text = 22.58 5.39 82.09 237
echo "NEW Cell"
grep "2555,20" out.2A25.20090308.64436.7.HDF.txt.text = 24.72 5.58 82.05 237
echo "NEW Cell"
grep "2557,20" out.2A25.20090308.64436.7.HDF.txt.text = 19.75 5.62 82.11 170
grep "2557,21" out.2A25.20090308.64436.7.HDF.txt.text = 24.34 5.58 82.13 120
grep "2558,22" out.2A25.20090308.64436.7.HDF.txt.text = 22.2 5.57 82.19 120
echo "NEW Cell"
grep "2560,22" out.2A25.20090308.64436.7.HDF.txt.text = 24.69 5.62 82.25 160
grep "2561,23" out.2A25.20090308.64436.7.HDF.txt.text = 24.74 5.60 82.30 120
echo "NEW Cell"
grep "2560,24" out.2A25.20090308.64436.7.HDF.txt.text = 19.38 5.54 82.30 170
echo "NEW Cell"
Теперь я хочу удалить строку с "grep" при условии, что это ЕДИНСТВЕННАЯ строка между строками, содержащими "New Cell". То есть, если между new cell есть одна строка grep, то эту строку нужно удалить.
Как это сделать?
Мой вывод должен выглядеть так:
echo "NEW Cell"
grep "2557,20" out.2A25.20090308.64436.7.HDF.txt.text = 19.75 5.62 82.11 170
grep "2557,21" out.2A25.20090308.64436.7.HDF.txt.text = 24.34 5.58 82.13 120
grep "2558,22" out.2A25.20090308.64436.7.HDF.txt.text = 22.2 5.57 82.19 120
echo "NEW Cell"
grep "2560,22" out.2A25.20090308.64436.7.HDF.txt.text = 24.69 5.62 82.25 160
grep "2561,23" out.2A25.20090308.64436.7.HDF.txt.text = 24.74 5.60 82.30 120
решение1
AWK
решение:
awk 'NR==n{ if (/NEW Cell/) { f=0 } else print r ORS gr }
/NEW Cell/{ f=1; n=NR+2; r=$0; next }
f && n-NR==1 && /^grep /{ gr=$0; next }1' file
/NEW Cell/{ f=1; n=NR+2; r=$0; next }
- при встрече с линиейNEW Cell
f=1
= установить активный флагf=1
n=NR+2
- установитьn
максимальное количество следующих строк для обработки (2 следующие строки)r=$0
- захват линииnext
- перейти к следующей записи
f && n-NR==1 && /^grep /
- при обнаружении 2-й строки (гарантируетсяn-NR==1
), которая начинается сgrep
ключевого словаgr=$0; next
- захватgrep
строки и переход к следующей (третьей) записи
NR==n{ if (/NEW Cell/) { f=0 } else print r ORS gr }
- при встрече с 3-й критической линией (обеспечиваетсяNR==n
)if (/NEW Cell/) { f=0 }
- если 3-я строка в обработанном разделе содержитNEW Cell
- сбросить текущую обработкуf=0
(все ранее захваченные строки пропускаются)else print r ORS gr
- в противном случае вывести все ранее захваченные строки
Выход:
echo "NEW Cell"
grep "2557,20" out.2A25.20090308.64436.7.HDF.txt.text = 19.75 5.62 82.11 170
grep "2557,21" out.2A25.20090308.64436.7.HDF.txt.text = 24.34 5.58 82.13 120
grep "2558,22" out.2A25.20090308.64436.7.HDF.txt.text = 22.2 5.57 82.19 120
echo "NEW Cell"
grep "2560,22" out.2A25.20090308.64436.7.HDF.txt.text = 24.69 5.62 82.25 160
grep "2561,23" out.2A25.20090308.64436.7.HDF.txt.text = 24.74 5.60 82.30 120
решение2
Компактное решение с sed
:
sed '/NEW Cell/!{H;d;};x;/\n.*\n/!d'
Если строка не содержит, NEW Cell
выполните H
добавление строки в область удержания и d
остановите обработку этой строки.
Поэтому дальнейшие команды применяются только к NEW Cell
строкам: x
Обменивает пространство шаблона и пространство удержания, таким образом, строка теперь находится в пространстве удержания, и могут быть добавлены дополнительные строки, в то время как пространство шаблона содержит все, что добавлено к последней NEW Cell
строке. Ваше требование заключается в том, чтобы между строками было больше одной строки NEW Cell
, поэтому в пространстве шаблона должно быть не менее двух новых строк. Если нет, удалите его без вывода: /\n.*\n/!d
.
решение3
С элементарными awk
...
Версия 1 удалит только grep
строки, которые следуют описанию OP:
awk '/^grep/ { if (f) { if (length(s) > 0) { print s; s="" } print } \
else { f=1; s=$0 } } ! /^echo/ { print; f=0 } \
! /^echo/ && ! /^grep/ { print }' inputfile
Версия 2 удалит отдельные grep
строки, а также предшествующую строку без grep, которая следует за примером вывода OP:
awk '/^grep/ { if (f) { if (length(s) > 0) { print s; s="" } print } \
else { f=1; s=s "\n" $0 } } /^echo/ { s=$0; f=0 } \
! /^echo/ && ! /^grep/ { print }' inputfile
Читабельная форма версии 2...
/^grep/ {
if (found) { # found==true : already encountered first grep line
if (length(save) > 0) {
print save
save=""
}
print
} else {
found=1
save=save "\n" $0 # append the first grep line to saved preceding line
}
}
/^echo/ {
save=$0 # save this line for possible later printing
found=0
}
# print anything else
! /^echo/ && ! /^grep/ { print }
Эту длинную форму можно запустить, поместив ее содержимое в файл (например, awkfile
) и awk -f awkfile inputfile
.
решение4
gawk '
/\n.+\n/{
printf("%s%s", RS, $0);
}' RS='echo "NEW Cell"\n' input.txt
Объяснение:
RS='echo "NEW Cell"\n'
-RS
разделитель входных записей, по умолчанию новая строка. Теперь он изменен наecho "NEW Cell"\n
, таким образом, все вхождения этой строки будут удалены, а все символы между ними станут элементом записи./\n.+\n/{
- только для записей, соответствующих этому шаблону - новая строка, один или несколько символов, новая строка. Таким образом, он соответствует только многострочным записям, однострочная запись не соответствует, поскольку имеет только один\n
.printf("%s%s", RS, $0);
- печатает запись, перед которой стоитRS
(echo "NEW Cell"\n
).
Выход
echo "NEW Cell"
grep "2557,20" out.2A25.20090308.64436.7.HDF.txt.text = 19.75 5.62 82.11 170
grep "2557,21" out.2A25.20090308.64436.7.HDF.txt.text = 24.34 5.58 82.13 120
grep "2558,22" out.2A25.20090308.64436.7.HDF.txt.text = 22.2 5.57 82.19 120
echo "NEW Cell"
grep "2560,22" out.2A25.20090308.64436.7.HDF.txt.text = 24.69 5.62 82.25 160
grep "2561,23" out.2A25.20090308.64436.7.HDF.txt.text = 24.74 5.60 82.30 120