Удалить строки, которые находятся между заданными шаблонами из файла (с помощью инструментов Unix)

У меня есть текстовый файл (точнее, CSV-файл в немецком стиле, т. е. разделенный точкой с запятой десятичная запятая), в каждой строке которого есть дата и значение измерения.
Есть фрагменты ошибочных значений, которые я хочу удалить перед дальнейшей работой. Я хотел бы сохранить эти нарезки в каком-нибудь сценарии, чтобы мои исправления были задокументированы, и я мог бы воспроизвести эти исправления, если это необходимо.

Строки выглядят так:

28.01.2005 14:48:38;5,166
28.01.2005 14:50:38;2,916
28.01.2005 14:52:38;0,000
28.01.2005 14:54:38;0,000
(long stretch of values that should be removed; could also be something else beside 0)
01.02.2005 00:11:43;0,000
01.02.2005 00:13:43;1,333
01.02.2005 00:15:43;3,250

Теперь я хотел бы сохранить список начальных и конечных шаблонов, таких как 28.01.2005 14:52:38 + 01.02.2005 00:11:43, и скрипт вырезал бы строки, соответствующие этим парам начала/конца, и все, что находится между ними.

Я думаю о том, чтобы взломать awk-скрипт, но, возможно, мне не хватает уже существующего инструмента.


person Florian Jenn    schedule 03.01.2010    source источник


Ответы (5)


Взгляните на sed:

sed '/start_pat/,/end_pat/d'

удалит строки между start_pat и end_pat (включительно).

Чтобы удалить несколько таких пар, вы можете объединить их с несколькими параметрами -e:

sed -e '/s1/,/e1/d' -e '/s2/,/e2/d' -e '/s3/,/e3/d' ...
person Alok Singhal    schedule 03.01.2010
comment
Большой! Я знал, что мне не хватает чего-то, что я всегда использовал sed с одиночными шаблонами и никогда не вспоминал, что он предлагает диапазоны. - person Florian Jenn; 04.01.2010
comment
Кроме того, я могу поместить выражения в файл, где я также могу использовать комментарии (с #). Тогда командная строка будет sed -f scriptfile <infile >outfile. - person Florian Jenn; 04.01.2010
comment
Будьте осторожны, если end_pat не существует, все в файле удаляется после start_pat. Кроме того, если у вас есть несколько вхождений любого из шаблонов, вы получите разные результаты в зависимости от порядка. - person FireEmerald; 21.02.2020

Во-первых, зачем вам вести учет того, что вы сделали? Почему бы не сохранить резервную копию исходного файла, или сравнить старые и новые файлы, или поставить их под контроль источника?

Для реальных изменений я предлагаю использовать Vim.

Команду Vim :global (сокращенно :g) можно использовать для запуска команд :ex в строках, соответствующих регулярному выражению. Это во многих отношениях более мощное, чем awk, поскольку команды могут затем ссылаться на диапазоны относительно соответствующей строки, плюс в вашем распоряжении есть все возможности Vim для обработки текста.

Например, это сделает что-то близкое к тому, что вы хотите (не проверено, так что будьте осторожны):

:g!/^\d\d\.\d\d\.\d\d\d\d/ -1 write tmp.txt >> | delete

Это сопоставляет строки, которые НЕ начинаются с даты (! отменяет совпадение), добавляет предыдущую строку в файл tmp.txt, а затем удаляет текущую строку.

Вероятно, вы получите повторяющиеся строки в tmp.txt, но их можно удалить, запустив файл через uniq.

person Dave Kirby    schedule 03.01.2010
comment
Я хотел бы делать короткие заметки о пластинках, которые я выбросил, и почему. Я буду работать с этими данными не очень часто, и я знаю, что могу забыть то, что я сделал. Кроме того, кому-то еще может понадобиться понять и воспроизвести то, что я сделал. К сожалению, ваш пример vi/ex на самом деле не решает мою проблему, потому что все строки начинаются с даты. Но я понимаю направление, которое вы указываете. - person Florian Jenn; 04.01.2010

вы также используете awk

awk '/start/,/end/' file
person ghostdog74    schedule 04.01.2010
comment
Где-то упоминалось, что awk подходит, когда данные представлены в формате столбца. Это правильно. Не могли бы вы объяснить, лучше ли awk для этой конкретной задачи. - person Talespin_Kit; 27.03.2014

Я бы серьезно посоветовал изучить основы Perl (т.е. не ООП). Он отплатит вам ведрами.

Чтобы сделать это (и многие другие подобные задачи), можно быстро и просто написать немного Perl, если вы усвоили основы, которые, если вы привыкли использовать awk, sed, grep и т. д., довольно просты.

Вам не нужно помнить, как использовать множество различных инструментов, и там, где раньше вы использовали несколько инструментов, соединенных вместе, для решения проблемы, вы можете просто использовать один сценарий perl (обычно намного быстрее для выполнения).

И Perl теперь установлен практически в каждом дистрибутиве Unix/Linux.

(хотя этот sed аккуратный :-)

person DaveC    schedule 04.01.2010

используйте grep -L (не печатайте ни одной совпадающей строки)

Извините - думал, вам просто нужны строки без 0,000 в конце

person Martin Beckett    schedule 03.01.2010
comment
grep -L будет печатать несовпадающие имена файлов. grep -v будет печатать несовпадающие строки, но OP, кажется, после чего-то более сложного (с использованием диапазонов). - person mopoke; 04.01.2010
comment
Хорошо, я думал, что они просто хотят напечатать что угодно без 0.000 в конце - person Martin Beckett; 04.01.2010
comment
Действительно, мой пример немного вводит в заблуждение, есть и другие ошибочные значения, кроме 0, например. отрицательные. - person Florian Jenn; 04.01.2010