Как удалить вторую строку последовательных строк, начинающихся с одного и того же слова?

у меня есть текстовый файл с взаимозаменяемыми строками, начинающимися с "TITLE" и "DATA", но иногда есть повторяющиеся строки, начинающиеся с "TITLE":

название что-то
Данные некоторые данные
Название-то другое
Данные некоторые другие данные
Название еще немного
Название дополнительная информация
Данные еще некоторые данные

Я хотел бы иметь возможность обнаруживать повторяющиеся строки, начинающиеся с "TITLE", и сохранять только первую строку каждая такая пара.
Я понял, что регулярное выражение для захвата этих ^TITLE.*n^TITLE.*n теперь я хотел бы включить это в однострочный perl/bash/sed/awk команда, которая удалит вторую строку и выведет остальную часть файла, но я не мог понять это.

5 ответов


решение Perl:

perl -ne 'print unless $t and /^TITLE/; $t = /^TITLE/'

Он помнит, была ли предыдущая строка заголовком в $t переменной.


вот один из способов сделать это с GNU sed:

sed -r 'N; /(TITLE)[^\n]*\n/ s/\n.*//; P; D' infile
  • N помещает вторую строку в пространство шаблона.
  • тест соответствия, если обе строки начинаются с TITLE.
  • если это так вторая линия удаляется.
  • P; D печать и удаление первой строки в пространстве шаблонов.

выход:

TITLE something
DATA some data
TITLE something else
DATA some other data
TITLE some more
DATA some more data

Edit-обрабатывать произвольное количество повторений

как отметил Никитину Reklawyks в комментариях приведенное выше решение работает только с двумя последовательными строками, начинающимися с TITLE, для обработки произвольного количества повторений, простой цикл может быть добавлен следующим образом:

sed -r ':a; N; /(TITLE)[^\n]*\n/ s/\n.*//; ta; P; D' infile

на ta заявление делает sed перейти к :a ярлык для s/// успешно.

другой способ сделать это - использовать С coreutils, это не так гибко, но тем не менее хорошо работает в этом дело:

uniq -w5 infile 

в одну сторону:

awk '!=p{print;p=}' file

мне кажется, что у вас есть записи, которые состоят из двух полей, заголовка и данных, и что если вам не хватает второго поля, вы хотите удалить запись. Но это не то, что ты задал в своем вопросе. Так вот один из способов сделать то, что вы просили:

awk '/^TITLE/&&!t{t=} /^DATA/&&t{print t;print;t=""}' inputfile

идея здесь в том, что мы установим переменную в заголовок, когда увидим его, и еще не имеем набора заголовков, а затем только распечатаем его, когда увидим данные. Это работает для входных данных, которые вы предоставили, если я читаю ваши Вопрос Правильный. Выход есть:

TITLE something
DATA some data
TITLE something else
DATA some other data
TITLE some more
DATA some more data

как вы можете видеть, последняя строка заголовка в вашем наборе данных была удалена.

и вот еще один способ сделать это в awk...

awk '/^TITLE/&&t{next} t=0; /^TITLE/{t=1} 1' inputfile

в этом, первое выражение пропускает заголовки, если t Бен поставил. Второе выражение расстраивает t. Третье выражение задает if для заголовков, а последнее выражение (1) печатает строку. Конечно, последние три выражения не запускаются, если мы пропустили строку в первое выражение. Он генерирует тот же результат, что и выше, и не утруждает себя просмотром /^DATA/.

наконец, это наименьший код, но самая странная логика:

awk '/^DATA/ || !t; {t=/^TITLE/}' inputfile

он печатает все строки данных, или любой линии, где t не установлен, а затем эффективно устанавливает t к логическому, влияющему на оценку следующей строки. Если вы делаете это в csh или tcsh, остерегайтесь восклицательного знака, который в этих оболочках может потребоваться избежать.


попробуйте этот однострочный:

 awk '/^TITLE/&&f{next;} {if (~/^TITLE/)f=1;else f=0}1' file

выход:

TITLE something
DATA some data
TITLE something else
DATA some other data
TITLE some more
DATA some more data