grep --before-context 5
pokazuje 5 linii przed meczem.
Chcę pokazać wszystko przed meczem.
Robienie grep --before-context 99999999
by działało, ale nie jest bardzo ... profesjonalne.
Jak wyświetlić cały plik do dopasowania?
grep --before-context 5
pokazuje 5 linii przed meczem.
Chcę pokazać wszystko przed meczem.
Robienie grep --before-context 99999999
by działało, ale nie jest bardzo ... profesjonalne.
Jak wyświetlić cały plik do dopasowania?
Odpowiedzi:
Sed jest do tego lepszy.
Po prostu zrób:
sed '/PATTERN/q' FILE
Działa to tak:
Dla każdej linii sprawdzamy, czy pasuje /PATTERN
:
Jest to najbardziej wydajne rozwiązanie, ponieważ gdy tylko zobaczy PATTERN
, przestaje działać. Bez tego q
sed nadal czytałby resztę pliku i nic z tym nie robił. W przypadku dużych plików może to mieć znaczenie.
Tej sztuczki można także użyć do emulacji head
:
sed 10q FILE
sed '/PATTERN/Q' FILE
pominie dopasowaną linię. Q
jest rozszerzeniem GNU, więc nie będzie działać z żadnym sedem.
sed
może zastąpić większość funkcjonalności grep.
sed -n '1,/<pattern>/ p' <file>
Oznacza to drukowanie od pierwszej linii, aż wzór zostanie dopasowany.
Kilka przykładów zakresu
sed -n '/<pattern>/,$ p' <file> # from pattern to end of file
sed -n '/<pattern1>/,/<pattern2>/ p' <file> # from pattern1 to pattern2
wydrukuj do meczu włącznie:
awk '{print} /pattern/ {exit}' filename
sed '/pattern/q' filename
wydrukuj do ALE NIE w tym meczu:
awk '/pattern/ {exit} {print}' filename
sed '/pattern/Q' filename
Q
fajny, ale specyficzny dla GNU afaik, sed -n '/pattern/!p;//q'
byłby bardziej przenośny.
!
sprawia, że p
stosuje się do linii nie pasujących pattern
, ale potem //q
myli mnie ...
//
oznacza „poprzednie wyrażenie regularne” (myślałem, że oznacza „dopasuj pusty ciąg”). Myślę, że krótsza wersja tego samego rozwiązania to sed -n '/pattern/q;p
:?
Następujące grep
metody czystego GNU nie są wydajne.
Wyszukaj wszystko do pierwszego wystąpienia ciągu „ foo ” na pasku plików , używając trzech grep
s:
grep -m 1 -B $(grep -n -m 1 foo bar | grep -o '^[0-9]*') foo bar
Dopasowane do ostatniej instancji „ foo ”:
grep -oPz "(?s)[^\n]*${s}.*?\n.*?foo.*?\n" bar
Uwaga: szczegółowe informacje na temat ostatniego grep
można znaleźć w: Regex (grep) do wyszukiwania wieloliniowego .
grep
s (+ pcre), gdy chodzi o proste uruchomienie pojedynczego sed
wywołania: sed 'x;/./G;//!x;/foo/p;//s/.*//;x;d'
??
sed
kod wydaje się wart własnej odpowiedzi lub może zostać dodany do jednego z pozostałych. Re 7 grep
s: Ponieważ nie było grep
odpowiedzi ... (plus, odpowiedź pomaga pokazać, dlaczego nie.)
Dodanie do odpowiedzi Mikela powyżej ...
Aby wydrukować wszystkie wiersze do pierwszego wiersza FILE
zawierającego PATTERN
, ale bez uwzględnienia , spróbuj:
sed '/.*PATTERN.*/{s///;q;}' FILE
Pasuje do całej linii zawierającej wzorzec, zastępuje ją pustą linią, a następnie kończy pracę bez przetwarzania reszty pliku.
Postscriptum:
Najłatwiejszym / najczystszym sposobem, jaki mogłem wymyślić, aby zapobiec drukowaniu dodatkowej nowej linii na końcu (bez angażowania innego narzędzia), było ponowne uruchomienie sed i usunięcie nowej ostatniej linii:
sed '/.*PATTERN.*/{s///;q;}' FILE | sed '$d'
... a ponieważ i tak usuwamy tę linię, nasza poprzednia praca jest zbędna i możemy uprościć:
sed '/PATTERN/q' FILE | sed '$d'
sed
wywołania.
tcsh
w bash
aliasie, jak i aliasu, musiałem się upewnić miał stosunkowo zwięzłe jedno-liniowe rozwiązanie, które działało zarówno w standardzie, jak i GNU sed
(w celu przenoszenia); wszystkie wymagania, które Twój wkład mógł bardzo dobrze spełnić. Jako ktoś, kto używa sed
bardzo rzadko, moim najważniejszym wymogiem było coś, co mogłem szybko zrozumieć, kiedy chcę łatwo edytować lub zmienić przeznaczenie za lata.
Dla osób, które decydują się pamiętać tylko podstawowe narzędzia w codziennej pracy i chcą zaakceptować mniej eleganckie i mniej wydajne rozwiązania:
head -n $(grep -n pattern filename | cut -d: -f1) filename
Jeśli to polecenie dotyczy skryptu, będę szukał bardziej eleganckich (i być może wydajnych) rozwiązań. Jeśli jest to jednorazowe polecenie lub skrypt wyrzucający, to mnie to nie obchodzi.
Możesz także użyć jednego z poniższych
tac ./test | grep -B $(cat ./test | wc -l) -m 1 'pattern'|tac
lub
tac ./test |head -n $(tac ./test | grep -n 'pattern' | cut -d: -f1 | head -n 1)|tac
lub
tac ./test |sed ':a;N;$!ba;s/\n/'"pattern"'/g' | sed 's/'"patternpattern"'/\n/g'|head -n 1|sed 's/'"pattern"'/\n/g'|tac
Pierwsza opcja jest bardzo podobna do sugerowanej przez PO, tylko upewnia się, że ti pokazuje wystarczającą liczbę linii przed kontekstem, zliczając linie w pliku
Druga opcja przeszukuje numer wiersza pierwszego dopasowania (możesz to również zmienić, zmieniając wewnętrzną „głowę”), a następnie używa głowy na tym numerze
Ostatnia opcja zastępuje wszystkie nowe linie dopasowaniem, a następnie zastępuje dwa sąsiednie dopasowania nową linią. Wynikiem tego jest wiersz dla każdego bloku tekstu między dwoma dopasowaniami. Następnie używa „head”, aby wybrać pierwszy wiersz (zmieniając blok tekstu do pierwszego dopasowania), a następnie ponownie tłumaczy każde dopasowanie do nowego wiersza. ta opcja działa tylko wtedy, gdy plik ma następujący format
pattern
texttexttext
texttexttext texttexttext
texttexttexttexttexttexttexttexttext
pattern
texttexttext
pattern
texttexttext
texttexttexttexttexttexttexttexttext
i tak dalej
sed
polecenie na dole jest dość srogie.