Как удалить одну линию между двумя строками

Как удалить одну линию между двумя строками

У меня есть миллионы записей в файле, которые выглядят так

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

Объяснение:

  1. RS='echo "NEW Cell"\n'- RSразделитель входных записей, по умолчанию новая строка. Теперь он изменен на echo "NEW Cell"\n, таким образом, все вхождения этой строки будут удалены, а все символы между ними станут элементом записи.
  2. /\n.+\n/{- только для записей, соответствующих этому шаблону - новая строка, один или несколько символов, новая строка. Таким образом, он соответствует только многострочным записям, однострочная запись не соответствует, поскольку имеет только один \n.
  3. 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

Связанный контент