Bagaimana cara mencetak semua baris setelah kecocokan hingga akhir file?

48

Input file1 adalah:

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

Saya memberikan kecocokan pola dari dalam other file(seperti dog 123 4335dari file2).

Saya cocok dengan pola garis itu dog 123 4335dan setelah mencetak semua garis tanpa garis cocok keluaran saya adalah:

cat 13123 23424
deer 2131 213132
bear 2313 21313

Jika hanya menggunakan tanpa alamat jalur hanya menggunakan pola, misalnya 1s bagaimana cara mencocokkan dan mencetak garis?

loganaayahee
sumber
Bisakah file lain hanya berisi satu pola untuk dicari, atau satu per baris, dan mulai mencari pada baris mana yang ditemukan pertama kali dalam file yang dicari?
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Jawaban:

27

Dengan asumsi Anda ingin mencocokkan keseluruhan garis dengan pola Anda, dengan GNU sed, ini berfungsi:

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

Setara standar:

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

Dengan input berikut ( infile):

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

Outputnya adalah:

cat 13123 23424 
deer 2131 213132
bear 2313 21313

Penjelasan:

  • /^dog 123 4335$/ mencari pola yang diinginkan.
  • :a; n; p; ba;adalah loop yang mengambil baris baru dari input ( n), mencetaknya ( p), dan bercabang kembali ke label a :a; ...; ba;.

Memperbarui

Inilah jawaban yang mendekati kebutuhan Anda, yaitu pola di file2, yang diambil dari file1:

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

Grep dan cut yang disematkan menemukan baris pertama yang berisi pola dari file2, nomor baris ini ditambah satu diteruskan ke ekor, plus satu ada di sana untuk melewati garis dengan pola.

Jika Anda ingin memulai dari pertandingan terakhir alih-alih pertandingan pertama adalah:

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

Perhatikan bahwa tidak semua versi ekor mendukung notasi plus.

Thor
sumber
Ini adalah contoh pertama dari perintah n dan p di sed yang telah saya lihat yang tidak terasa seperti mengambil sed terlalu jauh. Tampaknya (dari tes singkat saya) bahwa sed -n '/^dog 123 4335$/ { :a; p; n; ba; }' infile(dengan p dan n diaktifkan) berhasil memasukkan garis yang cocok juga.
Josiah Yoder
26

Jika Anda memiliki file yang cukup pendek grepsaja mungkin berfungsi:

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

5000 hanya dugaan saya di "cukup pendek", karena grepmenemukan kecocokan pertama dan output bersama dengan 5000 baris berikutnya (file tidak perlu memiliki banyak). Jika Anda tidak ingin pertandingan itu sendiri, Anda harus memotongnya, mis

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


Jika Anda tidak menginginkan yang pertama, tetapi kecocokan terakhir sebagai pembatas, Anda dapat menggunakan ini:

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

Baris ini membaca animals.txtdalam urutan terbalik dari baris dan output hingga dan termasuk baris dengan dog 123 4335dan kemudian berbalik lagi untuk mengembalikan urutan yang tepat.

Sekali lagi, jika Anda tidak membutuhkan kecocokan dalam hasilnya, tambahkan ekor. (Anda juga bisa menyulitkan ekspresi sed untuk membuang buffernya sebelum berhenti.)

Aet3miirah
sumber
Dengan pengujian saya, GNU grep 3.0 tidak menghasilkan lebih dari 132 baris setelah konteks (terlepas dari nilai yang ditentukan).
ruvim
22

Dalam prakteknya saya mungkin akan menggunakan jawaban Aet3miirah sebagian besar waktu dan jawaban alexey luar biasa ketika ingin menavigasi melalui garis (juga, itu juga berfungsi dengan less). OTOH, saya sangat menyukai pendekatan lain (yang merupakan jawaban terbalik dari Gilles :

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

Ketika dipanggil dengan -nflag, sedtidak mencetak secara default garis yang diprosesnya lagi. Kemudian kami menggunakan formulir 2-alamat yang mengatakan untuk menerapkan perintah dari baris yang cocok /dog 123 4335/sampai akhir file (diwakili oleh $). Perintah yang dimaksud adalah p, yang mencetak baris saat ini. Jadi, ini berarti "cetak semua garis dari yang cocok /dog 123 4335/sampai akhir."

brandizzi
sumber
3
Itu mencetak doggaris yang tidak diinginkan di sini.
Stéphane Chazelas
1
Ini sepertinya jawaban terbaik (dan berfungsi untuk kasus saya sendiri) tetapi perlu disesuaikan untuk melewati garis yang cocok juga.
Pavel Šimerda
1
sed -n '/ dog 123 4335 /, $ p' | sed '1d' akan menghapus garis anjing
Kemin Zhou
1
sed -n '/dog 123 4335/,$p' | tail -n +2akan menghapus pertandingan juga
gilad mayani
15
sed -e '1,/dog 123 4335/d' file1

Jika Anda perlu membaca pola dari file, gantikan dengan perintah sed. Jika file berisi pola sed:

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

Jika file berisi string literal yang harus dicari, kutip semua karakter khusus. Saya menganggap file tersebut berisi satu baris.

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

Jika Anda ingin kecocokan menjadi seluruh baris, bukan hanya substring, bungkus pola ^…$.

sed -e "1,/^$(sed 's/[][\\\/^$.*]/\\&/g' file2)\$/d" file1
Gilles 'SANGAT berhenti menjadi jahat'
sumber
6
Itu tidak akan berhasil jika polanya ada di baris pertama. GNU sedpunya 0,/dog.../duntuk itu.
Stéphane Chazelas
14

$ more +/"dog 123 4335" file1

alexey
sumber
4
Ini juga berfungsi dengan baik less.
brandizzi
3
pintar di terminal, tetapi tidak benar-benar bekerja jika Anda pipa itu menjadi sesuatu yang lain seperti tac.
jcomeau_ictx
saya menggunakannya seperti ini, $ lebih + / "cocokkan kata-kata saya" file1 >> file2
AMB
1
Mungkin +digantikan oleh -pdalam POSIX 7: pubs.opengroup.org/onlinepubs/9699919799/utilities/more.html tetapi belum diimplementasikan di util-linux 2.20.1. Dan ini juga mencetak skipping..dan beberapa baris baru (untuk stderr saya harapkan, jadi mungkin baik-baik saja).
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
mungkin hal-hal telah berubah sejak saat itu? komentar saya mendapat 3 upvotes sehingga mungkin relevan pada saat itu ...
jcomeau_ictx
11

Dengan awk:

awk 'BEGIN {getline pattern < "other file"}
   NR == 1, $0 ~ pattern {next}; {print}' < "input file"
Stéphane Chazelas
sumber
5

Salah satu cara menggunakan awk:

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

di mana file2 berisi pola pencarian Anda. Pertama, semua isi file2 disimpan dalam array "a". Ketika file1 diproses, setiap baris diperiksa terhadap array, dan dicetak hanya jika tidak ada.

Guru
sumber
Saya pikir OP ingin menampilkan setiap baris mengikuti pola.
Thor
@Thor: terima kasih sudah menunjukkannya, perbarui sekarang ...
Guru
Bagus sekali :).
Thor
5

Jika input adalah file biasa yang dapat dibaca :

Dengan GNU grep:

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

Dengan sed:

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

GNU grepbernama w / -mopsi akan berhenti input pada pertandingan - dan itu akan meninggalkan input (lseekable) fd segera setelah titik itu menemukan pertandingan terakhirnya. Jadi memanggil grepw / -m1menemukan kejadian pertama pola dalam file, dan daun masukan offset tepat pada tempat yang tepat untuk catuntuk menulis segala sesuatu mengikuti pertandingan pertama pola dalam file ke stdout.

Bahkan tanpa GNU grepAnda dapat melakukan hal yang sama persis dengan kompatibel POSIX sed- ketika sed qdigunakan ditentukan untuk membiarkan input offsetnya tetap di tempatnya. GNU sedtidak memenuhi standar dengan cara ini, dan karenanya di atas kemungkinan tidak akan bekerja dengan GNU sedkecuali jika Anda menyebutnya dengan -usaklarnya.

mikeserv
sumber
perhatikan, sedberbagi aliran yang diperlihatkan di sini tidak secara khusus (meskipun, ya, standar yang dirujuk tidak secara khusus contoh sedsebagai utilitas yang mampu) dari alur kerja bentuk-bebas dan kondisional yang ditunjukkan. terutama, semua utilitas standar dimaksudkan dan ditentukan untuk dengan demikian bekerja sama dan berbagi posisi kursor dari aliran input tanpa membuat proses berikutnya gagal bagi pembaca berikutnya. grep -qharus melakukan ini; diam grep- diam akan kembali segera setelah ditemukan kecocokan dalam input, dan sisa input tidak boleh, secara standar, dikonsumsi secara default.
mikeserv
4

Jawaban saya untuk pertanyaan dalam subjek, tanpa menyimpan pola dalam file kedua. Ini file pengujian saya:

$ 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

Varian Perl dengan pola dalam file:

$ 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
sumber
2

Dengan ed:

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

Ini mengirimkan satu pperintah rintisan ke ed dalam string di sini; perintah cetak dibatasi dalam kisaran satu setelah ( +1) dog 123 4335kecocokan hingga akhir file ( $).

Jeff Schaller
sumber
1

Jika Anda tidak keberatan dengan pembuatan file sementara, dan sudah csplittersedia, ini berfungsi:

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

Catatan file1adalah file input dan file2file pola (seperti yang dinyatakan dalam pertanyaan).

Bentuk panjang dari perintah di atas adalah:

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

yaitu,

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

csplittanpa prefixtanda di atas akan membuat file xx00(awalan sedang xx, dan akhiran sedang 00). Dengan bendera di atas itu menciptakan file file1_00. Tanpa quietflag, ia mencetak ukuran file output (ukuran file yang dihasilkan).

YenForYang
sumber
0

Karena awk tidak dilarang secara tegas, inilah penawaran saya dengan asumsi 'kucing' adalah pasangannya.

awk '$0 ~ /cat/ { vart = NR }{ arr[NR]=$0 } END { for (i = vart; i<=NR ; i++) print arr[i]  }' animals.txt
Tom
sumber
0

Bagaimana cara mencetak semua baris setelah kecocokan hingga akhir file?

Cara lain untuk menjelaskannya adalah "bagaimana menghapus semua baris dari baris pertama hingga yang cocok (termasuk)", dan ini dapat sedditulis sebagai:

sed -e '1,/MATCH PATTERN/d'
poige
sumber
1
Satu-satunya masalah adalah ketika polanya ada di baris pertama ...
don_crissti
1
Apakah ini berbeda dari unix.stackexchange.com/a/56517/32558 ?
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
Saya kira kita perlu komite di sini untuk memutuskan.
poige
1
@poige: nah, Anda memberikan jawaban yang sama kurang komprehensif
Thor
@don_crissti, sed -e '0,/MATCH PATTERN/d'lalu bagaimana?
Velkan