Grep mencari dua kata dalam satu baris

46

Saya sudah mencoba menemukan cara untuk menyaring garis yang memiliki kata "lemon" dan "nasi" di dalamnya. Saya tahu cara menemukan "lemon" atau "nasi" tetapi tidak keduanya. Mereka tidak perlu berada di sebelah yang lain, hanya satu baris teks yang sama.

Sebastian
sumber
1
Untuk menemukan semua string di dalam file, Anda dapat menjalankan grep di loop FOR: unix.stackexchange.com/a/462445/43233
Noam Manos

Jawaban:

62

"Keduanya pada baris yang sama" berarti "'nasi' diikuti oleh karakter acak diikuti oleh 'lemon' atau sebaliknya".

Di regex itu adalah rice.*lemonatau lemon.*rice. Anda dapat menggabungkannya menggunakan |:

grep -E 'rice.*lemon|lemon.*rice' some_file

Jika Anda ingin menggunakan regex normal alih-alih yang diperluas ( -E) Anda perlu garis miring terbalik sebelum |:

grep 'rice.*lemon\|lemon.*rice' some_file

Untuk lebih banyak kata yang dengan cepat menjadi agak panjang dan biasanya lebih mudah untuk menggunakan beberapa panggilan grep, misalnya:

grep rice some_file | grep lemon | grep chicken
Florian Diesch
sumber
Baris terakhir Anda adalah konjungsi bukan disjungsi, bukan? Wit: grep ricebaris-baris yang ditemukan mengandung rice. Ini dimasukkan ke dalam grep lemonyang hanya akan menemukan garis-garis yang mengandung lemon .. dan seterusnya. Sedangkan OP - serta jawaban Anda sebelumnya - memungkinkan salah satu [nasi | lemon | ayam]
javadba
Versi skrip: askubuntu.com/a/879253/5696
Jeff
@Florian Diesch - Pikiran menjelaskan mengapa |perlu melarikan diri grep? Terima kasih!
buron
1
@ Buronan egrepmenggunakan regex diperpanjang di mana |dipahami sebagai logika OR. grepdefault ke regex dasar, di mana \|OR
Sergiy Kolodyazhnyy
Sebagaimana dinyatakan dalam grephalaman manual, egrepsudah usang dan harus diganti oleh grep -E. Saya mengambil kebebasan untuk mengedit jawaban sesuai.
hidangan penutup
26

Anda dapat menyalurkan output dari perintah grep pertama ke perintah grep lain dan itu akan cocok dengan kedua pola. Jadi, Anda dapat melakukan sesuatu seperti:

grep <first_pattern> <file_name> | grep <second_pattern>

atau,

cat <file_name> | grep <first_pattern> | grep <second_pattern>

Contoh:

Mari kita tambahkan beberapa konten ke file kita:

$ echo "This line contains lemon." > test_grep.txt
$ echo "This line contains rice." >> test_grep.txt
$ echo "This line contains both lemon and rice." >> test_grep.txt
$ echo "This line doesn't contain any of them." >> test_grep.txt
$ echo "This line also contains both rice and lemon." >> test_grep.txt

Apa isi file:

$ cat test_grep.txt 
This line contains lemon.
This line contains rice.
This line contains both lemon and rice.
This line doesn't contain any of them.
This line also contains both rice and lemon.

Sekarang, mari kita ambil apa yang kita inginkan:

$ grep rice test_grep.txt | grep lemon
This line contains both lemon and rice.
This line also contains both rice and lemon.

Kami hanya mendapatkan garis di mana kedua pola cocok. Anda dapat memperpanjang ini dan menyalurkan output ke perintah grep lain untuk kecocokan "DAN" lebih lanjut.

Aditya
sumber
21

Meskipun pertanyaannya menanyakan 'grep', saya pikir mungkin bermanfaat untuk mengirim solusi 'awk' sederhana:

awk '/lemon/ && /rice/'

Ini dapat dengan mudah diperpanjang dengan lebih banyak kata, atau ekspresi boolean lain selain 'dan'.

David B.
sumber
11

Gagasan lain untuk menemukan kecocokan dalam urutan apa pun adalah menggunakan:

grep dengan opsi -P (Perl-Kompatibilitas) dan regex lookahead positif(?=(regex)) :

grep -P '(?=.*?lemon)(?=.*?rice)' infile

atau Anda dapat menggunakan di bawah ini, sebagai gantinya:

grep -P '(?=.*?rice)(?=.*?lemon)' infile
  • The .*?cara pencocokan karakter apapun .yang kejadian nol atau lebih kali *saat mereka berada opsional diikuti oleh pola ( riceatau lemon). The ?membuat segalanya opsional sebelum (berarti nol atau satu waktu dari segala sesuatu cocok .*)

(?=pattern): Positif Lookahead: Konstruk lookahead positif adalah sepasang tanda kurung, dengan tanda kurung buka diikuti oleh tanda tanya dan tanda sama dengan.

Jadi ini akan mengembalikan semua baris dengan berisi keduanya lemondan ricedalam urutan acak. Ini juga akan menghindari penggunaan |s dan doubled greps.


Tautan eksternal: Topik Grep Tingkat Lanjut Cari Positif - GREP untuk Desainer

αғsнιη
sumber
5
grep -e foo -e goo

Akan mengembalikan kecocokan untuk foo atau goo

netskink
sumber
1

Jika kita mengakui bahwa memberikan jawaban yang tidak grepdidasarkan adalah dapat diterima, seperti jawaban di atas berdasarkan awk, saya akan mengusulkan perlgaris sederhana seperti:

$ perl -ne 'print if /lemon/ and /rice/' my_text_file

Pencarian dapat mengabaikan kasus dengan beberapa / semua kata seperti /lemon/i and /rice/i. Pada sebagian besar mesin Unix / Linux perl diinstal juga sebagai awk.

Gilles Maisonneuve
sumber
Menolak!!! ;) Karena tidak masuk akal .. :)
An 26n
0

Berikut ini skrip untuk mengotomatiskan solusi grep piping:

#!/bin/bash

# Use filename if provided as environment variable, or "foo" as default
filename=${filename-foo}

grepand () {
# disable word splitting and globbing
IFS=
set -f
if [[ -n $1 ]]
then
grep -i "$1" ${filename} | filename="" grepand "${@:2}"
else
# If there are no arguments, assume last command in pipe and print everything
cat
fi
}

grepand "$@"
Jeff
sumber
1
Ini mungkin harus diimplementasikan menggunakan fungsi rekursif, alih-alih membangun string perintah dan evalmembuatnya, yang mudah rusak
muru
@muru Jangan ragu untuk menyarankan suntingan. Saya menghargai komentarnya.
Jeff
1
Mengeditnya akan terlalu banyak menulis ulang, jadi saya tidak akan melakukannya. Jika Anda ingin menambahkannya, inilah yang saya bayangkan akan terlihat seperti: paste.ubuntu.com/23915379
muru