Видаліть лінії, які не починаються з візерунка, із заданого набору шаблонів


11

У мене є файл, який містить такі дані:

report aaaaaaaa  
-  ..  
-th bbbbbbbbb  
-to ccccccccc

.. --.

Питання: Я хочу видалити будь-який рядок, який не починається з наступних рядків:

report  
-th  
-to

це означає, що результат бажання видалить усі ці середні небажані точки та хеші та матиме такий вигляд:

report aaaaaaaa  
-th bbbbbbbbb  
-to ccccccccc

sed// awk/ grepбудь-яке рішення, яке буде працювати.

Відповіді:


15

Використання sedдля зміни файлу на місці:

sed -i '/^\(report\|-t\(h\|o\)\)/!d' your_file

Це дає інструкцію sedвидалити всі рядки, що не відповідають шаблону. Сам шаблон - це ^(початок рядка), за яким послідує або reportабо -tпісля нього, hабо o.

Слід зазначити, що це не фактична модифікація на місці: sedстворює тимчасову резервну копію та перезаписує оригінальний файл із нею.

Якщо ви хочете sedзберегти резервну копію вихідного файлу (що може бути хорошою ідеєю, якщо файл містить критичні дані), надайте -iкомутатору розширення, щоб створити файл резервної копії:

sed -i'.bak' -e '/^\(report\|-t\(h\|o\)\)/!d' your_file

змінить your_fileта створить резервну копію оригіналу, що називається your_file.bak.

Бічна записка

Будь ласка, не помилково пояснюйте мої наміри чи не ображайтесь на це, але я помітив, що у вас є багато подібних питань, пов'язаних з регексом / обробкою тексту. Я раджу вам почати навчання sed, awkі grepна свій власний швидкості допомоги до вашої продуктивності. Знову ж, не зрозумійте мене неправильно, я дуже радий допомогти (як і більшість людей тут); це просто те, що я думаю, що ви виграєте величезну користь від підбору цих інструментів для щоденного використання.

Для того, щоб довести, наскільки тут корисні люди, врахуйте пропозицію @ slm в коментарях нижче та сміливо заходьте в цю чат будь-коли із запитаннями.


1
Ваше регулярне вираз здається надмірно виразним. Я думаю, ви насправді використовуєте більше символів, ніж якби ви тільки що явно перерахували три варіанти.
nispio

1
@nispio Я знаю, але це, ймовірно, буде ефективнішим, якщо файл, про який йде мова, великий.
Джозеф Р.

Цікаво. Я завжди вимірював регулярні вирази з точки зору довжини чи читабельності. Я ніколи не задумувався над швидкістю виконання. Я не думаю, що я знаю достатньо про те, як вони оцінюються, щоб судити про те, що швидко, але я припускаю, що це також є конкретною реалізацією, правда?
nispio

3
Повторіть повторення того, що Джозеф сказав про готовність допомогти, якщо у вас є загальні питання, які не відповідають стилю Q&A, ви завжди можете спробувати поспілкуватися з нами в кімнаті чатів для цього сайту. chat.stackexchange.com/rooms/26/unix-and-linux . Кілька з нас живе там 8-)
slm

@slm Дякую за це. Я додам це до своєї відповіді.
Джозеф Р.

10

Для цього можна використовувати простий греп:

$ grep -e '^report\|^-th\|^-to' filename

1
Це не велика економія, але ви можете комбінувати -th/ -toв -t[ho].
Кевін

grep -eабоegrep
Олів'є Дулак

2

Використання sed:

sed -n -e '/^report\|^-th\|^-to/p' filename

Це не велика економія, але ви можете комбінувати -th/ -toв -t[ho].
Кевін

1
@Kevin Це правда. Дивіться мою розмову з Джозефом Р. у коментарях до його відповіді.
nispio


1

Опитувач зробив два моменти:

  • бажаючи видалити будь-який рядок, що не починається з "звіту" чи "-тої" чи "-до".
  • потрібний вихід повинен видалити "всі ці середні небажані точки та хеші (sic)"

У цей час рішення стосуються першої точки, а отже, і другої. Але припустимо, що файл більший і виглядає так:

report aaaaaaaa  
-  ..  
-th bbbbbbbbb  
-to ccccccccc
anything else
.. --.
-tp ddd
-tq eee
     -  -----

Чи не буде звернення до другого пункту ОП потрібним?

sed -r -i.bak '/^[ |.|-]*$/d' input-file 

виконує роботу з видалення імовірно небажаних ліній, що містять просто пробіли, крапки і тире, та збереження решти, що б там не було.
Я думаю, що ризик будь-якого підходу полягає в тому, що природа файлу не визначена належним чином.


0

Використання Perl:

perl -ne 'print if /^report|^-t[ho]/' filename > newfile

або, щоб змінити на місці (наприклад sed, perlтакож буде зроблено тимчасову резервну копію, щоб це не було правдою в редагуванні місця ):

perl -i.bak -ne 'print if /^report|^-t[ho]/' filename

Це зробить копію оригінального файлу, що називається, filename.bakі замінить оригінальний файл відредагованою версією.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.