Usuń linie, które nie zaczynają się od wzoru z danego zestawu wzorów

11

Mam plik, który zawiera takie dane:

report aaaaaaaa  
-  ..  
-th bbbbbbbbb  
-to ccccccccc

.. --.

Pytanie: Chcę usunąć dowolny wiersz, który nie zaczyna się od następujących ciągów:

report  
-th  
-to

oznacza to, że wyjście pożądania usunie wszystkie środkowe niechciane kropki i skróty i będzie wyglądać następująco:

report aaaaaaaa  
-th bbbbbbbbb  
-to ccccccccc

sed/ awk/ grep/ itd. każde rozwiązanie, które będzie działać.

Rana Khan
źródło

Odpowiedzi:

15

Używając seddo modyfikacji pliku w miejscu:

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

To instruuje, sedaby usunąć wszystkie linie nie pasujące do wzorca. Wzór jest sama ^(start linii), a następnie przez jedną reportlub -tnastępnie albo hczy o.

Należy pamiętać, że nie jest to faktyczna modyfikacja na miejscu: sedtworzy tymczasową kopię zapasową i zastępuje ją oryginalnym plikiem.

Jeśli chcesz sedzachować kopię zapasową oryginalnego pliku (co może być dobrym pomysłem, jeśli plik zawiera krytyczne dane), podaj -iprzełącznikowi rozszerzenie, aby utworzyć plik kopii zapasowej:

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

zmodyfikuje your_filei utworzy kopię zapasową oryginału o nazwie your_file.bak.

Notatka dodatkowa

Proszę, nie mylcie moich intencji ani nie obrażajcie się na to, ale zauważyłem, że macie wiele podobnych pytań związanych z wyrażeniami regularnymi / przetwarzaniem tekstu. Radzę, aby rozpocząć naukę sed, awki grepna własną rękę do prędkości dopomóc swojej wydajności. Ponownie, nie zrozumcie mnie źle, jestem bardzo szczęśliwy, mogąc pomóc (podobnie jak większość ludzi tutaj); po prostu myślę, że możesz czerpać ogromne korzyści z podnoszenia tych narzędzi do codziennego użytku.

Aby udowodnić, jak pomocni są tutaj ludzie, zastanów się nad sugestią @ slm w komentarzach poniżej i zapraszam do tego czatu w dowolnym momencie na pytania.

Joseph R.
źródło
1
Twoje wyrażenie regularne wydaje się niepotrzebnie tajemnicze. Myślę, że tak naprawdę używasz więcej znaków, niż gdybyś wyraźnie wymienił trzy opcje.
nispio
1
@nispio Wiem, ale to może być bardziej wydajne, jeśli dany plik jest duży.
Joseph R.
Ciekawy. Zawsze mierzyłem wyrażenia regularne pod względem długości lub czytelności. Nigdy nie myślałem o szybkości egzekucji. Nie sądzę, że wiem wystarczająco dużo o tym, jak są one oceniane, aby ocenić, co jest szybkie, ale zakładam, że dotyczy to również implementacji, prawda?
nispio
3
Powtarzając to, co powiedział Joseph o chęci pomocy, jeśli masz ogólne pytania, które nie pasują do stylu pytań i odpowiedzi, zawsze możesz spróbować porozmawiać z nami na czacie na tej stronie. chat.stackexchange.com/rooms/26/unix-and-linux . Kilku z nas mieszka tam 8-)
slm
@slm Dziękuję za to. Dodam to do mojej odpowiedzi.
Joseph R.
10

Możesz do tego użyć prostego grep:

$ grep -e '^report\|^-th\|^-to' filename
pradeepchhetri
źródło
1
Nie jest to duża oszczędność, ale możesz połączyć -th/ -tow -t[ho].
Kevin,
grep -elubegrep
Olivier Dulac
2

Używanie sed:

sed -n -e '/^report\|^-th\|^-to/p' filename
nispio
źródło
Nie jest to duża oszczędność, ale możesz połączyć -th/ -tow -t[ho].
Kevin,
1
@Kevin To prawda. Zobacz moją rozmowę z Józefem R. w komentarzach do jego odpowiedzi.
nispio
2

Używanie awk:

awk '/^report|^-t[ho]/' file
jasonwryan
źródło
Nie jest to duża oszczędność, ale możesz połączyć -th/ -tow -t[ho].
Kevin,
1

Pytający podniósł dwie kwestie:

  • chce usunąć dowolny wiersz, który nie zaczyna się od „report”, „-th” lub „-to”.
  • pożądany wynik powinien usunąć „wszystkie te środkowe niechciane kropki i skróty (sic)”

Rozwiązania w tym momencie dotyczą pierwszego punktu, a tym samym również drugiego. Załóżmy jednak, że plik jest większy i wygląda następująco:

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

Czy zajęcie drugiego punktu OP nie byłoby konieczne?

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

wykonuje zadanie polegające na usuwaniu przypuszczalnie niechcianych linii zawierających tylko spacje, kropki i myślniki oraz zachowaniu reszty, cokolwiek to jest.
Sądzę, że ryzyko obu podejść polega na tym, że charakter pliku nie jest odpowiednio zdefiniowany.


źródło
0

Za pomocą Perla:

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

lub edytować w miejscu (jak sed, perlbędzie również tymczasową kopię zapasową, więc nie jest to prawdą w miejscu montażu):

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

Spowoduje to utworzenie kopii oryginalnego pliku o nazwie filename.baki zastąpienie oryginalnego pliku edytowaną wersją.

terdon
źródło