Grep ile tek bir satırda iki dizeyi eşleştirin


Yanıtlar:


189

Kullanabilirsiniz grep 'string1' filename | grep 'string2'

Veya, grep 'string1.*string2\|string2.*string1' filename


5
@AlexanderN gerçekten çok satırlı çalışmasını sağlayamıyorum, bu çok garip kabul edildi ..
Aquarius Power

1
Çok satırlı bir soru değildi. Çok satırlı olsaydı, grep -P Perl tarzı normal ifadeyi destekler ...
Scott Prive

20
Yalnızca 'dize1' VE 'dize2' aynı satırdayken çalışır. 'String1' veya 'string2' olan satırları bulmak istiyorsanız, user45949'un cevabına bakın.
lifeson106

10
ilk seçenek: bir grep'i bir saniyeye borulamak bir OR sonucu üretmez VE bir sonuç üretir.
masukomi

1
Ben kullandımgrep -e "string1" -e "string2"
Ravi Dhoriya ツ

198

Aradığın şey budur:

grep -E "string1|string2" filename

Bence bu cevaplar şöyle:

grep 'string1.*string2\|string2.*string1' filename

yalnızca ikisinin olduğu durumla eşleşir, biri veya diğeri veya her ikisi ile eşleşmez.


14
olmaz grep -e "string1" -e "string2" filenameaynı şeyi?
janosdivenyi

25
string1 VEYA string2 için nasıl grep budur. soru açıkça string1 AND string2 aradıklarını belirtir.
orion elenzil

9
Sorunun oldukça kesin olduğuna eminim:How do I match lines that contains *both* strings?
r0estir0bbe

Aynı çizgiyle yazdırabilir mi?
凡 凡

1
Bu cevap neden hala burada? Bu sorunun cevabı DEĞİLDİR.
Prometheus

26

Tüm kelimeleri herhangi bir sırada herhangi bir sırada içeren dosyaları aramak için:

grep -ril \'action\' | xargs grep -il \'model\' | xargs grep -il \'view_type\'

İlk grep özyinelemeli bir arama ( r) başlatır, büyük / küçük harf ( i) yoksayılır ve dosyanın herhangi bir yerinde gerçekleşen lbir terim () ile eşleşen ( ) dosyaların adını listeler (yazdırır) 'action'.

Sonraki grepsler, büyük / küçük harf duyarsızlığını koruyarak ve eşleşen dosyaları listeleyerek diğer terimleri arar.

Alacağınız dosyaların son listesi, bu terimleri içerenler, dosyanın herhangi bir yerinde herhangi bir sırada olacaktır.


2
Kabul! Sadece xargs'a boşluklu dosya adlarını işlemek için "-d '\ n'" vermek zorunda olduğumu not edeceğim. Bu benim için Linux'ta çalıştı: grep -ril 'foo' | xargs -d '\n' grep -il 'bar'
Tommy Harris

16

Eğer bir varsa grepbir ile -Psınırlı için seçenek perlregex kullanabileceğiniz

grep -P '(?=.*string1)(?=.*string2)'

üst üste binen dizelerle çalışma avantajına sahiptir. Ve mantığını daha doğrudan belirtebileceğiniz için, perlas kullanarak biraz daha basittir grep:

perl -ne 'print if /string1/ && /string2/'

1
En iyi cevap. Kabuk çok kolay ve hızlıdır, ancak desen karmaşıklaştığında Python veya Perl (veya Awk) kullanmalısınız. Saf kabukta (bu gün ne anlama geliyorsa) yapılabileceğini kanıtlamaya çalışırken başınızı duvara çarpmayın. Bir hatırlatma millet, bu araçlar mevcut bir kabuk betiğine dibble gömülü "bir astar" sözdiziminde kullanılabilir.
Scott Prive

12

Metodunuz neredeyse iyiydi, sadece -w eksik

grep -w 'string1\|string2' filename

1
En azından OS-X ve FreeBSD'de işe yarıyor! Benim tahminim başka bir şey üzerinde (ki OP tanımlamadı - umarım senin dışında birçok kullanıcı için doğru bir cevap aşağı almadım).
Leo

OS-X kullanıyorum. Belki de bunu doğru yapmıyorum? Yaptığım şeye bir göz atın: i.imgur.com/PFVlVAG.png
Ariel

1
Garip. Ben fark dosya içine grepping değil, ama, benim yöntem ls ile boru eğer, ben değil sonuç elde: imgur.com/8eTt3Ak.png - Her ikisi de OS-X 10.9.5 ( "grep (BSD grep) 2.5.1-FreeBSD") ve FreeBSD 10 ("grep (GNU grep) 2.5.1-FreeBSD"). Senin ne olduğunu merak ediyorum grep -V.
Leo

1
Örnekleriniz benim için çalışıyor: i.imgur.com/K8LM69O.png Fark, bu yöntemin alt dizeleri almaması, kendi başlarına tam dizeler olması gerektiğidir. Ben alt dizeleri aramak için grep içinde regexps inşa etmek gerekir sanırım. Böyle bir şey:grep -w 'regexp1\|regexp2' filename
Ariel

2
OP, string1 veya string2'yi eşleştirerek bir örnek gösterir ve her iki dizeyi de içeren satırların nasıl eşleştirileceğini sorar . Bu örnek hala OR sağlar.
gustafbstrom

7

|Bir normal ifade, operatör araçları ya da. Yani dize1 veya dize2 eşleşir. Şunları yapabilirsiniz:

grep 'string1' filename | grep 'string2'

bu da ilk komutun sonuçlarını ikinci grep'e aktarır. Bu size yalnızca her ikisiyle de eşleşen satırlar vermelidir.


1
İfadeleriniz doğru, ancak OP sorusuna cevap vermeyin
Ben Wheeler

Bu soruya cevap veriyor ve aslında çoğu insan bunu böyle yazıyor.
Peter K

7

Böyle bir şey deneyebilirsiniz:

(pattern1.*pattern2|pattern2.*pattern1)

4

Ve insanların perl ve python ve kıvrımlı kabuk komut dosyaları önerdiği gibi, burada basit bir awk yaklaşımı:

awk '/string1/ && /string2/' filename

Kabul edilen cevaba yapılan yorumlara baktığımızda: hayır, bu çok satırlı değildir; ama o zaman sorunun yazarı da bunu istemedi.


3

Bunun için grep kullanmaya çalışmayın, bunun yerine awk kullanın. Grep'te 2 regexps R1 ve R2'yi eşleştirmek için bunun olacağını düşünürdünüz:

grep 'R1.*R2|R2.*R1'

awk içinde iken:

awk '/R1/ && /R2/'

Peki R2ya bir alt kümesiyle çakışıyorsa ya da bir alt kümesi ise R1? Bu grep komutu, awk komutu çalışırken işe yaramaz. Eğer içeren satırları bulmak istiyorsunuz diyelim theve heat:

$ echo 'theatre' | grep 'the.*heat|heat.*the'
$ echo 'theatre' | awk '/the/ && /heat/'
theatre

Bunun için 2 vites ve bir boru kullanmanız gerekir:

$ echo 'theatre' | grep 'the' | grep 'heat'
theatre

ve tabii ki aslında ayrı olmalarını istediyseniz, her zaman grep'te kullandığınızla aynı regexp'i yazabilirsiniz ve regexps'leri her olası sırayla tekrarlamayı içermeyen alternatif awk çözümleri vardır.

Bunu bir kenara bırakırsak, çözümünüzü 3 regexps R1, R2 ve R3'e uyacak şekilde genişletmek isterseniz ne olur? Grep'te bu kötü seçimlerden biri olurdu:

grep 'R1.*R2.*R3|R1.*R3.*R2|R2.*R1.*R3|R2.*R3.*R1|R3.*R1.*R2|R3.*R2.*R1' file
grep R1 file | grep R2 | grep R3

awk iken kısa, açık, basit, verimli olurdu:

awk '/R1/ && /R2/ && /R3/'

Şimdi, gerçekte R1 ve R2 normal ifadeleri yerine S1 ve S2 değişmez dizelerini eşleştirmek isteseydiniz? Bunu grep'e yapılan bir çağrıda yapamazsınız, grep'i çağırmadan önce tüm RE metachar'lardan kaçmak için kod yazmanız gerekir:

S1=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< 'R1')
S2=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< 'R2')
grep 'S1.*S2|S2.*S1'

veya tekrar 2 greps ve bir boru kullanın:

grep -F 'S1' file | grep -F 'S2'

awk ile regexp operatörü yerine bir dize operatörü kullanırsanız:

awk 'index($0,S1) && index($0.S2)'

Şimdi, bir paragraf yerine bir satırda 2 normal ifadeyi eşleştirmek isteseydiniz? Grep'te yapılamaz, awk'de önemsizdir:

awk -v RS='' '/R1/ && /R2/'

Tüm bir dosyaya ne dersiniz? Yine grep'te yapılamaz ve awk'ta önemsizdir (bu sefer kısaltma için çoklu char RS için GNU awk kullanıyorum ama herhangi bir awk'da çok daha fazla kod yok veya bilmediğiniz bir kontrol-char seçebilirsiniz RS'nin aynısını yapması için girdi olması):

awk -v RS='^$' '/R1/ && /R2/'

Yani - bir satırda veya paragrafta veya dosyada birden fazla regexps veya dize bulmak istiyorsanız grep kullanmayın, awk kullanın.


Büyük / awk '/R1/ && /R2/'küçük harfe duyarlı değil mi?
Prometheus

@Hashim - hayır. Yapacağınız GNU awk awk -v IGNORECASE=1 '/R1/ && /R2/'ve herhangi bir awk ile büyük / küçük harfe duyarsız hale getirmek içinawk '{x=toupper($0)} x~/R1/ && x~/R2/'
Ed Morton

3
grep string1\|string2 FILENAME 

GNU grep sürüm 3.1


2

Yalnızca 6 boşlukla başlayan ve biten satırlar bulundu:

 cat my_file.txt | grep
 -e '^      .*(\.c$|\.cpp$|\.h$|\.log$|\.out$)' # .c or .cpp or .h or .log or .out
 -e '^      .*[0-9]\{5,9\}$' # numers between 5 and 9 digist
 > nolog.txt

2

Diyelim ki bir dosya test dosyasında birden çok kelimenin sayısını bulmamız gerekiyor. Bu konuda iki yol var

1) Normal ifade eşleme deseniyle grep komutunu kullanın

grep -c '\<\(DOG\|CAT\)\>' testfile

2) egrep komutunu kullanın

egrep -c 'DOG|CAT' testfile 

Egrep ile ifade hakkında endişelenmenize ve kelimeleri bir boru ayırıcıyla ayırmanıza gerek yoktur.


2

git grep

git grepBirden çok desenle kullanılan sözdizimi şöyledir :

git grep --all-match --no-index -l -e string1 -e string2 -e string3 file

Ayrıca , ve gibi Boole ifadeleriyle desenleri birleştirebilirsiniz .--and--or--not

man git-grepYardım olup olmadığını kontrol edin .


--all-matchBirden çok desen ifadesi verirken, bu işaretin eşleşmeyi, hepsiyle eşleşecek satırları olan dosyalarla sınırlaması için belirtilir .

--no-index Geçerli dizinde Git tarafından yönetilmeyen dosyaları arayın.

-l/ --files-with-matches/ --name-onlyYalnızca dosya adlarını göster.

-eBir sonraki parametre kalıptır. Varsayılan temel regexp kullanmaktır.

Dikkate alınması gereken diğer parametreler:

--threads Kullanılacak grep işçisi iş parçacığı sayısı.

-q/ --quiet/ --silentEşleşen satırları çıktılamayın; bir eşleşme olduğunda 0 durumuyla çıkın.

Desen türünü değiştirmek için ayrıca kullanabilir -G/ --basic-regexp(varsayılan), -F/ --fixed-strings, -E/ --extended-regexp, -P/ --perl-regexp, -f fileve diğer.

İlişkili:

İçin YA operasyonu, bkz:


2
Her zaman "git grep" in sadece bir git deposunun içinde çalıştırılabileceğini düşündüm. --No-index seçeneğinin farkında değildim. Gösterdiğiniz için teşekkürler!
Kamaraju Kusumanchi

1

Grep yapmak istediğiniz dizeleri bir dosyaya yerleştirin

echo who    > find.txt
echo Roger >> find.txt
echo [44][0-9]{9,} >> find.txt

Ardından -f tuşunu kullanarak arama yapın

grep -f find.txt BIG_FILE_TO_SEARCH.txt 

1
grep '(string1.*string2 | string2.*string1)' filename

herhangi bir sırayla string1 ve string2 ile satır alır


Bu en azından ilk iki cevaptan ne şekilde farklı?
luk2302

1
grep -i -w 'string1\|string2' filename

Bu, tam kelime eşleşmesi ve büyük / küçük harfe duyarlı olmayan kelimeler için çalışır, çünkü -i kullanılır


0

çok satırlı maç için:

echo -e "test1\ntest2\ntest3" |tr -d '\n' |grep "test1.*test3"

veya

echo -e "test1\ntest5\ntest3" >tst.txt
cat tst.txt |tr -d '\n' |grep "test1.*test3\|test3.*test1"

sadece yeni satır karakterini kaldırmamız gerekiyor ve işe yarıyor!


0

Bunun grepgibi olmalı :

$ grep 'string1' file | grep 'string2'

1
Bu mantıksal bir AND gerçekleştirir. OP mantıklı bir OR istiyor.
Ben Wheeler

1
@BenWheeler: Sorudan: "Peki grep ile sadece her iki dizeyi de içeren satırları nasıl eşleştirebilirim?"
Erik I

0

Sık sık seninkiyle aynı problemle karşılaşıyorum ve sadece bir senaryo yazdım:

function m() { # m means 'multi pattern grep'

    function _usage() {
    echo "usage: COMMAND [-inH] -p<pattern1> -p<pattern2> <filename>"
    echo "-i : ignore case"
    echo "-n : show line number"
    echo "-H : show filename"
    echo "-h : show header"
    echo "-p : specify pattern"
    }

    declare -a patterns
    # it is important to declare OPTIND as local
    local ignorecase_flag  filename linum header_flag colon result OPTIND

    while getopts "iHhnp:" opt; do
    case $opt in
        i)
        ignorecase_flag=true ;;
        H)
        filename="FILENAME," ;;
        n)
        linum="NR," ;;
        p)
        patterns+=( "$OPTARG" ) ;;
        h)
        header_flag=true ;;
        \?)
        _usage
        return ;;
    esac
    done

    if [[ -n $filename || -n $linum ]]; then
    colon="\":\","
    fi

    shift $(( $OPTIND - 1 ))

    if [[ $ignorecase_flag == true ]]; then
    for s in "${patterns[@]}"; do
            result+=" && s~/${s,,}/"
    done
    result=${result# && }
    result="{s=tolower(\$0)} $result"
    else
    for s in "${patterns[@]}"; do
            result="$result && /$s/"
    done
    result=${result# && }
    fi

    result+=" { print "$filename$linum$colon"\$0 }"

    if [[ ! -t 0 ]]; then       # pipe case
    cat - | awk "${result}"
    else
    for f in "$@"; do
        [[ $header_flag == true ]] && echo "########## $f ##########"
        awk "${result}" $f
    done
    fi
}

Kullanımı:

echo "a b c" | m -p A 
echo "a b c" | m -i -p A # a b c

İsterseniz .bashrc içine koyabilirsiniz.


0

Her iki dizge de sıralandığında, on grepkomutunun arasına bir desen koyun :

$ grep -E "string1(?.*)string2" file

Aşağıdaki satırlar aşağıdaki dosyada bulunuyorsa örnek Dockerfile:

FROM python:3.8 as build-python
FROM python:3.8-slim

Dizeleri içeren satırı almak için: FROM pythonve as build-pythonsonra şunu kullanın:

$ grep -E "FROM python:(?.*) as build-python" Dockerfile

Ardından çıktı yalnızca her iki dizeyi de içeren satırı gösterir :

FROM python:3.8 as build-python

-2

ripgrep

İşte örnek rg:

rg -N '(?P<p1>.*string1.*)(?P<p2>.*string2.*)' file.txt

Rust'un arama işlemini çok hızlı hale getirmek için sonlu otomata, SIMD ve agresif gerçek optimizasyonları kullanan regex motorunun üzerine inşa edildiğinden, en hızlı selamlama araçlarından biridir .

Özellikle büyük bir veri ile çalışırken kullanın.

GH-875'teki ilgili özellik isteğine de bakın .


1
Bu cevap pek doğru değil. Adlandırılmış yakalama grupları gereksizdir ve bu daha string2önce göründüğünde durumu ele almaz string1. Bu sorunun en basit çözümü rg string1 file.txt | rg string2.
BurntSushi5
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.