Jak wydrukować wszystkie linie po dopasowaniu do końca pliku?

48

Plik wejściowy 1 to:

dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

Daję dopasowaniu wzór z other file(jak dog 123 4335z pliku 2).

Dopasowuję wzór linii dog 123 4335i po wydrukowaniu wszystkich linii bez linii dopasowania, mój wynik to:

cat 13123 23424
deer 2131 213132
bear 2313 21313

Jeśli użyjesz tylko bez adresu linii, użyj tylko wzoru, na przykład 1s jak dopasować i wydrukować linie?

loganaayahee
źródło
Czy inny plik może zawierać tylko jeden wzorzec do wyszukania lub jeden w wierszu i rozpocząć wyszukiwanie od linii znajdującej się najpierw w szukanym pliku?
Ciro Santilli 14 改造 中心 法轮功 六四 事件

Odpowiedzi:

27

Zakładając, że chcesz dopasować całą linię do swojego wzoru, z GNU sed, działa to:

sed -n '/^dog 123 4335$/ { :a; n; p; ba; }' infile

Standardowy odpowiednik:

sed -ne '/^dog 123 4335$/{:a' -e 'n;p;ba' -e '}' infile

Z następującymi danymi wejściowymi ( infile):

cat 13123 23424 
deer 2131 213132
bear 2313 21313
dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

Dane wyjściowe to:

cat 13123 23424 
deer 2131 213132
bear 2313 21313

Wyjaśnienie:

  • /^dog 123 4335$/ szuka żądanego wzoru.
  • :a; n; p; ba;to pętla, która pobiera nowy wiersz z input ( n), drukuje go ( p) i rozgałęzia z powrotem, aby oznaczyć a :a; ...; ba;.

Aktualizacja

Oto odpowiedź, która zbliża się do twoich potrzeb, tj. Wzorzec w pliku 2, grepowanie z pliku 1:

tail -n +$(( 1 + $(grep -m1 -n -f file2 file1 | cut -d: -f1) )) file1

Osadzony grep i cut znajdują pierwszą linię zawierającą wzór z pliku2, ten numer linii plus jeden jest przekazywany do ogona, plus jeden służy do pominięcia linii ze wzorem.

Jeśli chcesz zacząć od ostatniego meczu zamiast pierwszego, byłoby to:

tail -n +$(( 1 + $(grep -n -f file2 file1 | tail -n1 | cut -d: -f1) )) file1

Pamiętaj, że nie wszystkie wersje ogona obsługują notację plusa.

Thor
źródło
To pierwszy przykład komend n i p w sed, które widziałem, i nie mam ochoty posunąć sed zbyt daleko. Wydaje się (z moich krótkich testów), że sed -n '/^dog 123 4335$/ { :a; p; n; ba; }' infile(przy przełączonych p i n) z powodzeniem zawiera również pasującą linię.
Josiah Yoder
26

Jeśli masz dość krótki grepsam plik , może działać:

grep -A5000 -m1 -e 'dog 123 4335' animals.txt

Domyślam się, że 5000 jest „dość krótkie”, ponieważ grepznajduje pierwsze dopasowanie i wysyła je wraz z następnymi 5000 liniami (plik nie musi mieć tak wielu). Jeśli nie chcesz samego dopasowania, musisz je odciąć, np

grep -A5000 -m1 -e 'dog 123 4335' animals.txt | tail -n+2


Jeśli nie chcesz pierwszego, ale ostatniego dopasowania jako separatora, możesz użyć tego:

tac animals.txt | sed -e '/dog 123 4335/q' | tac

Ta linia odczytuje animals.txtw odwrotnej kolejności linie i wyjścia do linii włącznie z linią, dog 123 4335a następnie ponownie cofa, aby przywrócić prawidłową kolejność.

Ponownie, jeśli nie potrzebujesz dopasowania w wyniku, dołącz ogon. (Możesz także skomplikować wyrażenie sed, aby odrzucić jego bufor przed zakończeniem.)

Aet3miirah
źródło
W moim teście GNU grep 3.0 nie wyświetla więcej niż 132 wierszy w kontekście późniejszym (niezależnie od określonej wartości).
ruvim
22

W praktyce prawdopodobnie używałbym odpowiedzi Aet3miirah przez większość czasu, a odpowiedź Alexeya jest cudowna, gdy chce się poruszać po liniach (również działa z less). OTOH, naprawdę podoba mi się inne podejście (które jest rodzajem odwróconej odpowiedzi Gillesa :

sed -n '/dog 123 4335/,$p'

Po wywołaniu z -nflagą sednie drukuje domyślnie linii, które przetwarza. Następnie używamy 2-adresowego formularza, który mówi, aby zastosować polecenie od dopasowania linii /dog 123 4335/do końca pliku (reprezentowanego przez $). Polecenie p, o którym mowa , drukuje bieżący wiersz. Oznacza to więc „wydrukuj wszystkie linie od jednego pasującego /dog 123 4335/do końca”.

brandizzi
źródło
3
To drukuje doglinię, która nie jest tutaj pożądana.
Stéphane Chazelas,
1
To wygląda na najlepszą odpowiedź (i działa w moim przypadku), ale musiałoby zostać dostosowane, aby pominąć również dopasowaną linię.
Pavel Šimerda
1
sed -n '/ dog 123 4335 /, $ p' | sed '1d' usunie linię psów
Kemin Zhou
1
sed -n '/dog 123 4335/,$p' | tail -n +2usunie również mecz
gilad mayani
15
sed -e '1,/dog 123 4335/d' file1

Jeśli chcesz odczytać wzorzec z pliku, zastąp go poleceniem sed. Jeśli plik zawiera wzorzec sed:

sed -e "1,/$(cat file2)/d" file1

Jeśli plik zawiera dosłowny ciąg do wyszukania, wpisz wszystkie znaki specjalne. Zakładam, że plik zawiera jedną linię.

sed -e "1,/$(sed 's/[][\\\/^$.*]/\\&/g' file2)/d" file1

Jeśli chcesz, aby dopasowaniem była cała linia, a nie tylko podciąg, zawiń wzór ^…$.

sed -e "1,/^$(sed 's/[][\\\/^$.*]/\\&/g' file2)\$/d" file1
Gilles „SO- przestań być zły”
źródło
6
To nie zadziała, jeśli wzór będzie w pierwszej linii. GNU sedma 0,/dog.../dna to.
Stéphane Chazelas,
14

$ more +/"dog 123 4335" file1

Alexey
źródło
4
Działa również z less.
brandizzi
3
sprytny na terminalu, ale tak naprawdę nie działa, jeśli wpiszesz go w coś innego tac.
jcomeau_ictx
używam go w ten sposób, $ więcej + / „dopasuj moje słowa” plik1 >> plik2
AMB
1
Być może +został zastąpiony przez -pPOSIX 7: pubs.opengroup.org/onlinepubs/9699919799/utilities/more.html, ale nie został jeszcze zaimplementowany w util-linux 2.20.1. I to również drukuje skipping..i kilka nowych linii (do stderr oczekuję, więc może być w porządku).
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
może od tamtej pory wszystko się zmieniło? mój komentarz uzyskał 3 głosy poparcia, więc mogło być istotne w tym czasie ...
jcomeau_ictx
11

Z awk:

awk 'BEGIN {getline pattern < "other file"}
   NR == 1, $0 ~ pattern {next}; {print}' < "input file"
Stéphane Chazelas
źródło
5

Jednym sposobem jest użycie awk:

awk 'NR==FNR{a[$0];next}f;($0 in a){f=1}'  file2 file1

gdzie plik2 zawiera wzorce wyszukiwania. Po pierwsze, cała zawartość pliku2 jest przechowywana w tablicy „a”. Podczas przetwarzania pliku1 każdy wiersz jest sprawdzany względem tablicy i drukowany tylko wtedy, gdy nie jest obecny.

Guru
źródło
Myślę, że OP chce wypisać każdy wiersz zgodny ze wzorem.
Thor
@Thor: dziękuję za zwrócenie uwagi, zaktualizowałem teraz ...
Guru
Ładnie wykonane :).
Thor
5

Jeśli dane wejściowe są zwykłym plikiem możliwym do zobaczenia :

Z GNU grep:

{ grep  -xFm1 'dog 123 4335' >&2
  cat; } <infile 2>/dev/null >outfile

Z sed:

{ sed -n '/^dog 123 4335$/q'
  cat; } <infile >outfile

GNU o grepnazwie w / -mopcja przerwie wprowadzanie podczas dopasowania - i opuści swoje (możliwe do zobaczenia) wejście fd natychmiast po punkcie, w którym znalazł swoje ostatnie dopasowanie. Tak więc wywołanie grepw / -m1znajduje pierwsze wystąpienie wzorca w pliku i pozostawia przesunięcie wejściowe dokładnie w odpowiednim miejscu catdo zapisania wszystkiego po pierwszym dopasowaniu wzorca do pliku na standardowe wyjście.

Nawet bez GNU grepmożesz zrobić dokładnie to samo z kompatybilnym z POSIX sed- kiedy sed quits jest określony, aby pozostawić przesunięcie wejściowe dokładnie tam, gdzie to robi. GNU sednie jest jednak w ten sposób zgodny ze standardami, więc powyższe prawdopodobnie nie będzie działać z GNU, sedchyba że wywołasz go za pomocą -uprzełącznika.

mikeserv
źródło
Uwaga: sedpokazane tutaj współdzielenie strumienia nie jest specjalnie (choć tak, wspomniany standard podaje konkretny przykład sedjako narzędzie, które jest w ten sposób zdolne) pokazanego swobodnego przepływu pracy. w szczególności wszystkie standardowe narzędzia są przeznaczone i określone do współpracy i współdzielenia pozycji kursorów strumieni wejściowych, nie powodując przy tym żadnego przetwarzania żadnego następnego czytnika. grep -qpowinien to zrobić; po cichu greppowinien powrócić, gdy tylko zostanie znalezione dopasowanie w danych wejściowych, a wszelkie pozostałe dane wejściowe nie powinny być standardowo zużywane.
mikeserv
4

Moja odpowiedź na pytanie w temacie, bez zapisywania wzoru w drugim pliku. Oto mój plik testowy:

$ cat animals.txt 
cat 13123 23424 
deer 2131 213132
bear 2313 21313
dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

GNU sed:

 $ sed '0,/^dog 123 4335$/d' animals.txt 
 cat 13123 23424 
 deer 2131 213132
 bear 2313 21313

Perl:

$ perl -ne 'print unless 1.../^dog 123 4335$/' animals.txt
cat 13123 23424 
deer 2131 213132
bear 2313 21313

Wariant Perla ze wzorem w pliku:

$ cat pattern.txt 
dog 123 4335
$ perl -ne 'BEGIN{chomp($p=(<STDIN>)[0])};print unless 1../$p/;' animals.txt < pattern.txt
cat 13123 23424 
deer 2131 213132
bear 2313 21313
jbgood
źródło
2

Wth ed:

ed -s file1 <<< '/dog 123 4335/+1,$p'

To wysyła jedno ppolecenie rint do ed w ciągu tutaj; polecenie drukowania jest ograniczone w zakresie do jednego po ( +1) dog 123 4335dopasowaniu do końca pliku ( $).

Jeff Schaller
źródło
1

Jeśli nie przeszkadza ci utworzenie pliku tymczasowego i masz go do csplitdyspozycji, działa to:

sh -c 'csplit -sf"$1_" "$1" "%^$(cat "$2")%+1" && cat "${1}_00"' sh file1 file2

Uwaga file1jest plikiem wejściowym i plikiem file2wzoru (jak podano w pytaniu).

Długa postać powyższego polecenia to:

sh -c 'csplit --quiet --prefix="$1_" "$1" "%^$(cat "$2")%+1" && cat "${1}_00"' sh file1 file2

to znaczy,

csplit --quiet --prefix="file1_" "file1" "%^$(cat "file2")%+1" && cat "file1_00"

csplitbez prefixpowyższej flagi utworzyłby plik xx00(prefiks xxi sufiks 00). Z flagą powyżej tworzy plik file1_00. Bez quietflagi drukuje rozmiar pliku wyjściowego (rozmiar pliku wynikowego).

YenForYang
źródło
0

Ponieważ awk nie jest wyraźnie niedozwolone, oto moja oferta, zakładając, że „kot” jest dopasowany.

awk '$0 ~ /cat/ { vart = NR }{ arr[NR]=$0 } END { for (i = vart; i<=NR ; i++) print arr[i]  }' animals.txt
Tomek
źródło
0

Jak wydrukować wszystkie linie po dopasowaniu do końca pliku?

Innym sposobem na określenie tego jest „jak usunąć wszystkie wiersze z pierwszego do dopasowania (w tym)”, i można to sednapisać jako:

sed -e '1,/MATCH PATTERN/d'
poige
źródło
1
Jedynym problemem jest to, że wzór znajduje się w pierwszej linii ...
don_crissti
1
Czy różni się to od unix.stackexchange.com/a/56517/32558 ?
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
Wydaje mi się, że potrzebujemy tutaj komisji do podjęcia decyzji.
poige
1
@poige: nie, podajesz tę samą odpowiedź mniej wyczerpująco
Thor
@don_crissti, a co sed -e '0,/MATCH PATTERN/d'wtedy?
Velkan,