Bisakah grep hanya menampilkan kata-kata yang cocok dengan pola pencarian?

685

Apakah ada cara untuk membuat "kata" grep output dari file yang cocok dengan ekspresi pencarian?

Jika saya ingin menemukan semua contoh, katakanlah, "th" di sejumlah file, saya dapat melakukan:

grep "th" *

tetapi hasilnya akan seperti (berani adalah saya);

beberapa teks-berkas: the cat duduk di dalam tikar  
beberapa-lain-text file: yang cepat rubah cokelat  
yet-another-text-file: saya harap ini menjelaskannya secara menyeluruh 

Apa yang ingin saya hasilkan, menggunakan pencarian yang sama, adalah:

the
the
the
this
thoroughly

Apakah ini mungkin menggunakan grep? Atau menggunakan kombinasi alat lainnya?

Neil Baldwin
sumber
2
Solusi Dan Midwood bekerja dengan sempurna dan layak mendapatkan kredit.
hakish
Apakah ada cara orang dapat mencetak kata-kata yang cocok tanpa mengubah garis. Sebaliknya string yang cocok harus tetap berada di baris yang sama?
Ahli Bahasa

Jawaban:

955

Coba grep -o

grep -oh "\w*th\w*" *

Sunting: cocok dengan komentar Phil

Dari dokumen :

-h, --no-filename
    Suppress the prefixing of file names on output. This is the default
    when there is only  one  file  (or only standard input) to search.
-o, --only-matching
    Print  only  the matched (non-empty) parts of a matching line,
    with each such part on a separate output line.
Dan Midwood
sumber
9
@ user181548, Opsi grep -o hanya berfungsi untuk GNU grep. Jadi jika Anda tidak menggunakan GNU grep, itu mungkin tidak berfungsi untuk Anda.
ksinkar
5
@ ABB Tergantung apakah Anda ingin menampilkan nama file yang cocok atau tidak. Saya tidak yakin dalam kondisi apa yang ditampilkan dan tidak ditampilkan, tetapi saya tahu bahwa ketika saya menggunakan grep di sejumlah direktori, ia menampilkan path file lengkap untuk semua file yang cocok, sedangkan dengan -h itu hanya menampilkan kata yang cocok tanpa spesifikasi apa pun tentang file itu. Jadi, untuk mencocokkan pertanyaan awal, saya pikir itu perlu dalam keadaan tertentu.
LokMac
1
Saya membutuhkan penjelasan untuk apa "\w*th\w*" *artinya, jadi saya pikir saya akan memposting. \wadalah [_ [: alnum:]], jadi ini pada dasarnya cocok dengan "kata" apa pun yang berisi 'th' (karena \wtidak termasuk spasi). Bagian * setelah kutipan adalah gumpalan untuk file mana (yaitu, mencocokkan semua file dalam direktori ini)
jeremysprofile
1
\wumumnya tidak portabel untuk grep -E; untuk portabilitas yang tepat, gunakan nama kelas karakter POSIX [[:alnum:]]saja (atau [_[:alnum:]]jika Anda benar-benar menginginkan garis bawah juga; atau coba grep -Pjika platform Anda memilikinya).
tripleee
@ ABB Mengingat output yang diinginkan ditampilkan oleh OP yang -hsepenuhnya perlu saya katakan ..?
El Ronnoco
81

Jawaban aman distribusi silang (termasuk windows minGW?)

grep -h "[[:alpha:]]*th[[:alpha:]]*" 'filename' | tr ' ' '\n' | grep -h "[[:alpha:]]*th[[:alpha:]]*"

Jika Anda menggunakan versi grep yang lebih lama (seperti 2.4.2) yang tidak termasuk opsi -o. Gunakan yang di atas. Lain gunakan yang lebih sederhana untuk mempertahankan versi di bawah ini.

Linux cross distribution jawaban aman

grep -oh "[[:alpha:]]*th[[:alpha:]]*" 'filename'

Untuk merangkum -ohoutput ekspresi reguler cocok dengan konten file (dan bukan nama file), sama seperti bagaimana Anda mengharapkan ekspresi reguler bekerja di vim / etc ... Apa kata atau ekspresi reguler yang akan Anda cari, terserah kamu! Selama Anda tetap ke POSIX dan bukan sintaks perl (lihat di bawah)

Lebih banyak dari manual untuk grep

-o      Print each match, but only the match, not the entire line.
-h      Never print filename headers (i.e. filenames) with output lines.
-w      The expression is searched for as a word (as if surrounded by
         `[[:<:]]' and `[[:>:]]';

Alasan mengapa jawaban awal tidak bekerja untuk semua orang

Penggunaan \wbervariasi dari platform ke platform, sebagai sintaks "perl" yang diperpanjang. Dengan demikian, instalasi grep yang terbatas untuk bekerja dengan kelas karakter POSIX menggunakan [[:alpha:]]dan tidak setara dengan perl \w. Lihat halaman Wikipedia pada ekspresi reguler untuk lebih lanjut

Pada akhirnya, jawaban POSIX di atas akan jauh lebih dapat diandalkan terlepas dari platform (menjadi yang asli) untuk grep

Sedangkan untuk dukungan grep tanpa opsi -o, grep pertama menampilkan garis yang relevan, tr membagi spasi ke baris baru, filter grep akhir hanya untuk masing-masing baris.

(PS: Saya tahu sebagian besar platform sekarang, pasti telah ditambal untuk \ w .... tetapi selalu ada yang tertinggal)

Penghargaan untuk solusi "-o" dari jawaban @AdamRosenfield

PicoCreator
sumber
1
Bagaimana dengan -o yang hanya bekerja di GNU grep (seperti ksinkar disebutkan dalam komentar pada jawaban yang diterima)?
Brilliand
@Brilliand hmm, saya mengalami kesulitan menemukan implementasi linux yang tidak mendukung '-o', saya dapat mencari kerja di sekitar jika saya tahu platform mana yang harus diperiksa.
PicoCreator
@ pico -oOpsi ini tidak ada di grep windows yang menginstal dengan paket git (minGW?): "c:\Program Files (x86)\Git\bin\grep" --version grep (GNU grep) 2.4.2
Bruce Peterson
@BrucePeterson saya telah menambahkan jawaban solusi AdamRosenfield untuk -o: Bantu saya memeriksa apakah windows git termasuk tr / sed dan versinya. Jadi saya dapat memeriksa apakah solusi ini bekerja
PicoCreator
@pico: untuk GIT: GNU versi sed 4.2.1, tr (GNU textutils) 2.0
Bruce Peterson
46

Ini lebih sederhana dari yang Anda pikirkan. Coba ini:

egrep -wo 'th.[a-z]*' filename.txt #### (Case Sensitive)

egrep -iwo 'th.[a-z]*' filename.txt  ### (Case Insensitive)

Dimana,

 egrep: Grep will work with extended regular expression.
 w    : Matches only word/words instead of substring.
 o    : Display only matched pattern instead of whole line.
 i    : If u want to ignore case sensitivity.
Abhinandan prasad
sumber
2
Ini sepertinya tidak menambah apa pun atas jawaban yang ada dari 4+ tahun sebelumnya.
tripleee
3
@ tripleee Saya menemukan pendekatan saya lebih baik dan sederhana jadi saya memposting ini.
Abhinandan prasad
42

Anda bisa menerjemahkan spasi ke baris baru dan kemudian menangkap, misalnya:

cat * | tr ' ' '\n' | grep th
Adam Rosenfield
sumber
18
tidak perlu kucing. tr '' '\ n' <file | grep th. Lambat untuk file besar.
ghostdog74
Ini tidak berhasil. Output masih berisi nama file dan seluruh baris dari file yang berisi kecocokan. Bagaimanapun, salah satu solusi lain yang ditawarkan berhasil. Terima kasih atas masukannya.
Neil Baldwin
@ ghostdog74: bagus, meskipun jika Anda memiliki lebih dari file, Anda harus menggunakan cat. @Neil Baldwin: Anda yakin mengetiknya dengan benar? Ketika hanya ada satu file input (stdin dalam kasus ini), grep tidak mencetak nama file.
Adam Rosenfield
@ Adam - ya, maaf Adam, ini berfungsi dengan satu file tetapi tidak banyak.
Neil Baldwin
4
@ ghostdog74 jika bagian yang lambat adalah karena tr, ia bisa melakukannya grepterlebih dahulu, jadi trakan diterapkan hanya pada baris yang cocok:grep th filename | tr ' ' '\n' | grep th
Carcamano
37

Hanya awk, tidak perlu kombinasi alat.

# awk '{for(i=1;i<=NF;i++){if($i~/^th/){print $i}}}' file
the
the
the
this
thoroughly
ghostdog74
sumber
8
@AjeetGanga yah, ada namanya
Daerdemandt
11

perintah grep hanya untuk pencocokan dan perl

grep -o -P 'th.*? ' filename
Raghu
sumber
3
Bagaimana dengan tampilan hanya grup yang cocok?
Bishwas Mishra
Ini tidak berfungsi; itu hanya akan pernah ditemukan thkarena Anda meminta pengulangan sesingkat mungkin dari wildcard.
tripleee
@ tripleee - tidak akan ada masalah, karena ada ruang yang disertakan di akhir regex. Namun, itu akan kehilangan kata-kata yang tidak memiliki spasi setelahnya, misalnya di ujung baris.
Ken Williams
8

Saya tidak puas dengan sintaks awk yang sulit diingat tetapi saya menyukai gagasan menggunakan satu utilitas untuk melakukan ini.

Sepertinya ack (atau ack-grep jika Anda menggunakan Ubuntu) dapat melakukan ini dengan mudah:

# ack-grep -ho "\bth.*?\b" *

the
the
the
this
thoroughly

Jika Anda menghilangkan flag -h yang Anda dapatkan:

# ack-grep -o "\bth.*?\b" *

some-other-text-file
1:the

some-text-file
1:the
the

yet-another-text-file
1:this
thoroughly

Sebagai bonus, Anda dapat menggunakan --outputflag untuk melakukan ini untuk pencarian yang lebih kompleks dengan sintaks termudah yang saya temukan:

# echo "bug: 1, id: 5, time: 12/27/2010" > test-file
# ack-grep -ho "bug: (\d*), id: (\d*), time: (.*)" --output '$1, $2, $3' test-file

1, 5, 12/27/2010
Pesolek
sumber
8
cat *-text-file | grep -Eio "th[a-z]+"
Mumbling Mac
sumber
2
atau hanya grep -Eio "th [az] +" nama file
Shayan
3
Mungkin melihat juga penggunaan yang tidak berguna cat?
tripleee
4

Untuk mencari semua kata dengan mulai dengan "ikon-" perintah berikut ini berfungsi dengan sempurna. Saya menggunakan Ack di sini yang mirip dengan grep tetapi dengan opsi yang lebih baik dan format yang bagus.

ack -oh --type=html "\w*icon-\w*" | sort | uniq
Sandeep
sumber
3

Anda juga dapat mencoba pcregrep . Ada juga -wopsi dalam grep , tetapi dalam beberapa kasus tidak berfungsi seperti yang diharapkan.

Dari Wikipedia :

cat fruitlist.txt
apple
apples
pineapple
apple-
apple-fruit
fruit-apple

grep -w apple fruitlist.txt
apple
apple-
apple-fruit
fruit-apple
Maciek Sawicki
sumber
3

Saya punya masalah yang sama, mencari grep / pola regex dan "pola cocok ditemukan" sebagai keluaran.

Pada akhirnya saya menggunakan egrep (regex yang sama pada grep -e atau -G tidak memberi saya hasil yang sama dari egrep) dengan opsi -o

jadi, saya pikir itu bisa menjadi sesuatu yang mirip (Saya BUKAN regex Master):

egrep -o "the*|this{1}|thoroughly{1}" filename
keebOo
sumber
{1}Pengukur yang tidak berguna harus dijatuhkan. Atau jika Anda ingin konsisten, t{1}h{1}e{1}dll.
tripleee
dapatkah ia mencetak dengan garis yang sama?
吴毅 凡
-1

Anda bisa menyalurkan output grep Anda ke Perl seperti ini:

grep "th" * | perl -n -e'while(/(\w*th\w*)/g) {print "$1\n"}'

sumber
9
itu tidak akan memberikan hasil yang benar. juga, jika menggunakan Perl, tidak perlu menggunakan grep. lakukan segalanya di Perl.
ghostdog74
Terima kasih telah menunjukkan kesalahannya, ghostdog74. Saya telah mengubahnya untuk mencetak semua kata di telepon, bukan hanya yang pertama.
seperti yang saya katakan, grep tidak perlu. perl -n -e'while (/ (\ s + th \ w *) / g) {print "$ 1 \ n"} 'file
ghostdog74
7
terserah kamu. Saya hanya menggambarkan suatu hal. Jika tidak perlu, jangan lakukan itu. tambahan itu "|" akan dikenakan biaya satu proses lebih banyak.
ghostdog74
1
Di Perl 5.10 atau lebih baru: perl -nE '@a = / (regexp) / ig; katakan bergabung "\ n", @a '
Profesor Photon
-1
$ grep -w

Kutipan dari halaman manual grep:

-w: Pilih hanya baris yang berisi kecocokan yang membentuk seluruh kata. Pengujiannya adalah bahwa substring yang cocok harus berada di awal baris, atau didahului oleh karakter konstituen non-kata.

pl1nk
sumber
1
Itu masih akan mencetak seluruh baris yang berisi pertandingan. Ini membatasi pertandingan yang sebenarnya sehingga thetidak lagi cocok misalnya "ini" atau "mandi".
tripleee
-6

ripgrep

Berikut ini contoh penggunaannya ripgrep:

rg -o "(\w+)?th(\w+)?"

Ini akan cocok dengan semua kata yang cocok th.

kenorb
sumber