Boru karakterine sahip deseni olan birden fazla desen için nasıl grep yapabilirim?


624

İki diziden birine uyan birkaç dosyadaki tüm satırları bulmak istiyorum. Aradığım modelleri yazarak bulmaya çalıştım

grep (foo|bar) *.txt

ancak kabuk |boruyu yorumlar ve barçalıştırılabilir olmadığında şikayet eder .

Aynı dosya setinde birden fazla deseni nasıl bulabilirim?



grep 'word1 \ | word2 \ | word3' / yol / dosyaya /
lambodar

Yanıtlar:


861

İlk önce, deseni kabuk tarafından genişlemekten korumanız gerekir. Bunu yapmanın en kolay yolu, etrafına tek tırnak koymaktır. Tek tırnak, aralarındaki herhangi bir şeyin genişlemesini önler (ters eğik çizgiler dahil); O zaman yapamayacağınız tek şey, düzende tek tırnak işareti kullanmaktır.

grep 'foo*' *.txt

Tek bir alıntıya ihtiyacınız varsa, şunu yazabilirsiniz '\''(son dizgi değişmez, değişmez teklif, açık dizgi değişmez).

grep 'foo*'\''bar' *.txt

İkincisi, grep, desenler için iki sözdizimini destekler. Eski, varsayılan sözdizimi ( normal normal ifadeler ) alternation ( |) operatörünü desteklemiyor, ancak bazı sürümlerde bunun bir uzantısı var, ancak ters eğik çizgi ile yazılmış.

grep 'foo\|bar' *.txt

Taşınabilir yöntem, yeni sözdizimini, genişletilmiş düzenli ifadeleri kullanmaktır . Seçmek için -Eseçeneği grepgeçmeniz gerekir. Linux'ta egrepbunun yerine da yazabilirsiniz grep -E(diğer birimlerde, bunu bir diğer ad yapabilirsiniz).

grep -E 'foo|bar' *.txt

Sadece birkaç kalıptan herhangi birini ararken (ayrılma kullanarak karmaşık bir kalıp oluşturmak yerine) çoklu kalıplara geçmektir grep. Bunu, her bir kalıbı -eseçeneğiyle birlikte izleyerek yapabilirsiniz .

grep -e foo -e bar *.txt

18
Bir sınır olarak - kalıplar sabitlendiğinde, gerçekten alışkanlık edinmelisin fgrepya da grep -Fküçük kalıplar için fark ihmal edilebilir, ancak uzadıkça, faydalar gösterilmeye başlıyor ...
TC1

7
@ TC1 fgrep adam sayfasına göre itiraz edildi
RAMN

18
@ TC1 grep -FGerçek bir performans avantajına sahip olup olmadığı grep uygulamasına bağlıdır: bazıları yine de aynı algoritmayı uygular, böylece -Fyalnızca deseni ayırmak için harcanan zamana değil, aramaya zaman harcayarak fark eder. -FÖrneğin GNU grep daha hızlı değildir (çok grep -Fbaytlı yerel ayarlarda daha da yavaşlayan bir hatadır - aynı sabit kalıp grepaslında çok daha hızlıdır!). Öte yandan BusyBox grep, -Fbüyük dosyalardan çok yarar sağlar.
Gilles,

4
Belki de, değişimin sadece normal ifadenin bir parçası olacağı daha karmaşık modeller için , "\ (" ve "\)" ile birlikte gruplanabileceğinden söz edilmelidir. ) (?).
Peter Mortensen

4
Not egrepöncedir grep -E. GNU'ya özgü değildir (kesinlikle Linux ile ilgisi yoktur). Aslında, hala varsayılanın grepdesteklemediği Solaris gibi sistemleri bulacaksınız -E.
Stéphane Chazelas

90
egrep "foo|bar" *.txt

veya

grep "foo\|bar" *.txt
grep -E "foo|bar" *.txt

gnu-grep’in man sayfasını seçici olarak göstererek:

   -E, --extended-regexp
          Interpret PATTERN as an extended regular expression (ERE, see below).  (-E is specified by POSIX.)

Matching Control
   -e PATTERN, --regexp=PATTERN
          Use PATTERN as the pattern.  This can be used to specify multiple search patterns, or to protect  a  pattern
          beginning with a hyphen (-).  (-e is specified by POSIX.)

(...)

   grep understands two different versions of regular expression syntax: basic and extended.”  In  GNU grep,  there
   is  no  difference  in  available  functionality  using  either  syntax.   In  other implementations, basic regular
   expressions are less powerful.  The following description applies to extended regular expressions; differences  for
   basic regular expressions are summarized afterwards.

Başlangıçta daha fazla okumadım, bu yüzden ince farklılıkları tanımadım:

Basic vs Extended Regular Expressions
   In basic regular expressions the meta-characters ?, +, {, |, (, and ) lose their special meaning; instead  use  the
   backslashed versions \?, \+, \{, \|, \(, and \).

Her zaman egrep ve gereksiz yere parens kullandım, çünkü örneklerden öğrendim. Şimdi yeni bir şey öğrendim. :)


22

TC1'in dediği -Fgibi, kullanılabilir seçenek olarak görünüyor:

$> cat text
some text
foo
another text
bar
end of file

$> patterns="foo
bar" 

$> grep -F "${patterns}" text
foo
bar

1
@poige $ 'foo \ nbar' seçeneği hakkında bir fikrim yoktu, buradaki genişlemenin nasıl çalıştığından emin değilim, bakmam gerekiyor, ama teşekkür ederim, bu gerçekten faydalıdır.
haridsv

Güzel! Bu seçenek aynı zamanda daha hızlı çalışmasını sağlıyor gibi görünüyor (regex'i devre dışı bıraktığı için).
qwertzguy

15

Öncelikle, özel karakterler için tırnak kullanmanız gerekir. İkincisi, öyle olsa bile, grepdoğrudan değişmeyi anlamayacak; kullanmanız gerekir egrepveya ( grepyalnızca GNU ile ) grep -E.

egrep 'foo|bar' *.txt

(Değişiklik daha büyük bir regex'in bir parçası olmadığı sürece parantez gerekli değildir.)


4
Aslında, grep -Edaha standart egrep.
jw013

8

Düzenli ifadelere ihtiyacınız yoksa, kullanmak fgrepveya daha grep -Ffazla ee parametresi kullanmak için çok daha hızlı , şunun gibi:

fgrep -efoo -ebar *.txt

fgrep(alternatif olarak grep -F) normal grep'ten çok daha hızlıdır çünkü normal ifadeler yerine sabit dizeleri arar.


4
Lütfen bu sayfadaki fgrep, kullanımdan kaldırıldığına dair yorumları da okuyun .
phk

6

Sonuç almak için aşağıdaki komutu deneyebilirsiniz:

egrep 'rose.*lotus|lotus.*rose' some_file

3

Birden fazla desen bulmak için ucuz ve neşeli bir yol:

$ echo "foo" > ewq ; echo "bar" >> ewq ; grep -H -f ewq *.txt ; rm ewq

Bir açıklamadan faydalanabilir.
Peter Mortensen,

2
Açıklama, grep'in -fseçeneğinin birden fazla desen içeren bir dosya almasıdır. Geçici bir dosya oluşturmak yerine (daha sonra silmeyi unutabilirsiniz), sadece kabuğun işlem değiştirmesini kullanın:grep -f <(echo foo; echo bar) *.txt
Jakob

3

Pipe ( |) özel bir kabuk karakteridir, bu nedenle ya kaçması ( \|) ya da manüel ( man bash) uyarınca alıntılanması gerekir :

Alıntılama, belirli karakterlerin veya kelimelerin kabuğa olan özel anlamlarını kaldırmak için kullanılır . Özel karakterler için özel işlemi devre dışı bırakmak, rezerve edilmiş kelimelerin tanınmasını önlemek ve parametre genişlemesini önlemek için kullanılabilir.

Karakterleri çift tırnak işareti içine almak gerçek değeri korur içine alma, tırnak içindeki tüm karakterlerin

Alınmamış ters eğik çizgi ( \), kaçış karakteridir.

Bakınız: Bash'de hangi karakterlerden kaçılması gerekiyor?

İşte birkaç örnek (henüz bahsedilmeyen araçları kullanarak):

  • Kullanarak ripgrep:

    • rg "foo|bar" *.txt
    • rg -e foo -e bar *.txt
  • Kullanarak git grep:

    • git grep --no-index -e foo --or -e bar

      Not: Ayrıca --and, --orve gibi Boolean ifadelerini de destekler --not.

Satır başına AND işlemi için, bakınız: Birden fazla AND deseniyle grep nasıl çalıştırılır?

Dosya başına VE işlemi için, bakınız: Bir dosyada bulunan birden çok dizenin veya regex'in tümü nasıl kontrol edilir?


3

Tarihlerin aptalca biçimlendirildiği erişim günlükleri vardı: [30 / Jun / 2013: 08: 00: 45 +0200]

Ama şunu göstermem gerekiyordu: 30 / Jun / 2013 08:00:45

Sorun şu ki grep ifademde "VEYA" kullanarak, iki ayrı ifadeyi iki ayrı satırda aldım.

İşte çözüm:

grep -in myURL_of_interest  *access.log  | \
grep -Eo '(\b[[:digit:]]{2}/[[:upper:]][[:lower:]]{2}/[[:digit:]]{4}|[[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}\b)'   \
| paste - - -d" " > MyAccess.log

2

TL; DR: Birden fazla düzenden birini eşleştirdikten sonra daha fazla şey yapmak istiyorsanız, bunları \(pattern1\|pattern2\)

Örnek: 'date' adını içeren bir değişkenin String veya int olarak tanımlandığı tüm yerleri bulmak istiyorum. (örneğin, "int cronDate =" veya "String textFormattedDateStamp ="):

cat myfile | grep '\(int\|String\) [a-zA-Z_]*date[a-zA-Z_]* =' 

İle grep -E, sen yani parantez veya boru, kaçmak gerek yok,grep -E '(int|String) [a-zA-Z_]*date[a-zA-Z_]* ='


1

Bu benim için çalışıyor

root@gateway:/home/sshuser# aws ec2 describe-instances --instance-ids i-2db0459d |grep 'STATE\|TAG'

**STATE**   80      stopped

**STATE**REASON     Client.UserInitiatedShutdown    Client.UserInitiatedShutdown: User initiated shutdown

**TAGS**    Name    Magento-Testing root@gateway:/home/sshuser#

1

Bunu yapmanın birden fazla yolu var.

  1. grep 'foo\|bar' *.txt
  2. egrep 'foo|bar' *.txt
  3. find . -maxdepth 1 -type f -name "*.txt" | xargs grep 'foo\|bar'
  4. find . -maxdepth 1 -type f -name "*.txt" | xargs egrep 'foo|bar'

3. ve 4. seçenek yalnızca dosyalara taşınır ve .txtadlarında yer alan dizinlerden kaçınır .
Bu nedenle, kullanım durumunuza göre, yukarıda belirtilen seçeneklerden herhangi birini kullanabilirsiniz.
Teşekkürler!!


0

@ geekosaur'un yanıtına eklemek için , sekmeleri ve alanı da içeren birden fazla şablonunuz varsa, aşağıdaki komutu kullanın

grep -E "foo[[:blank:]]|bar[[:blank:]]"

[[:blank:]]Bir boşluk veya sekme karakteri ya temsil YENİDEN olan karakter sınıfı

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.