Awk kullanarak eşleşen normal ifade kalıbı nasıl yazdırılır?


110

Kullanarak awk, bir dosyada normal ifade kalıbı ile eşleşen bir kelime bulmam gerekiyor.

Ben sadece desenle eşleşen kelimeyi yazdırmak istiyorum.

Yani eğer satırdaysa:

xxx yyy zzz

Ve desen:

/yyy/

Sadece almak istiyorum:

yyy

DÜZENLEME: kurumi sayesinde şöyle bir şey yazmayı başardım:

awk '{
        for(i=1; i<=NF; i++) {
                tmp=match($i, /[0-9]..?.?[^A-Za-z0-9]/)
                if(tmp) {
                        print $i
                }
        }
}' $1

ve ihtiyacım olan şey bu :) çok teşekkürler!


1
@maxtaldykin Kendi cevabınızı sorudan ayrı bir cevaba kaydırır mısınız lütfen?
kenorb

2
Yapmanıza gerek yok tmp=match($i, /regexp);if(tmp){}, sadece yapabilmelisiniz if(tmp ~ $i){}çünkü ~"regexp ile eşleşir" anlamına gelir.
JustinCB

Yanıtlar:


148

Bu çok temel

awk '/pattern/{ print $0 }' file

sormak awkaramak için patternkullanan //, daha sonra $ 0 ile gösterilir varsayılan olarak rekor denir hattı, çıktısını. En azından belgeleri okuyun .

Yalnızca eşleşen kelimeyi yazdırmak istiyorsanız.

awk '{for(i=1;i<=NF;i++){ if($i=="yyy"){print $i} } }' file

50
Yana printvarsayılan eylemdir: awk '/pattern/' fileyeterli olacaktır.
Johnsyweb

18
@Johnsyweb, evet bu gerçeği biliyorum. Marverix gibi yeni başlayanlar için daha görsel olması gerekiyordu.
kurumi

21
Bilginizden şüphe etmiyorum. Bununla birlikte, bilgi, bu yanıtı bulan başkalarına faydalı olabilir.
Johnsyweb

2
NB: @marverix, for(a) "yyy" normal bir ifade ise ve düz bir dize değilse ve (b) "yyy" içindeki tüm bir alanla eşleşmiyorsa , -döngüyü çalıştırmak için biraz daha ödev yapmak zorunda kalacak rekor.
Johnsyweb

8
Olmaz $i=="yyy"; $i ~ /yyy/normal bir ifade için olacaktır .
JustinCB

118

GNU'nun grep -odavranışını taklit etmeye çalışıyorsunuz gibi görünüyor . Bu, her satırda yalnızca ilk eşleşmeyi istemeniz koşuluyla bunu sağlayacaktır:

awk 'match($0, /regex/) {
    print substr($0, RSTART, RLENGTH)
}
' file

İşte GNU'nun awkuygulamasını kullanan bir örnek ():

awk 'match($0, /a.t/) {
    print substr($0, RSTART, RLENGTH)
}
' /usr/share/dict/words | head
act
act
act
act
aft
ant
apt
art
art
art

Hakkında okuyun match, substr, RSTARTve RLENGTHde awkmanuel.

Bundan sonra, aynı hat üzerindeki birden fazla maçla ilgilenmek için bunu uzatmak isteyebilirsiniz.


NB: Bu son bölümü cevaplamak için, ihtiyaç duyulan tüm yapılar kurumi'nin cevabında ve bana ait.
Johnsyweb

Mükemmel cevap. Sadece burada yerinde bir açıklama istiyorum çünkü tembelim. Ama bu yüzden AWK kullanıyorum!
lukas.pukenis

Maç sonucunu yazdırmak dışında bir şey yapmak istersem ne olur? Örneğin, tüm eşleşmeleri diziye eklemek istiyorum.
Evya2005

@ evya2005: Ron yazısını ihtiyacınız olan atama ile değiştirebilirsiniz.
Johnsyweb

benim için çalışmıyor. sadece baskı işi. bana örnek gösterebilir misin
Evya2005

36

gawk , bunu eylem olarak kullanarak her satırın eşleşen kısmını alabilir:

{ if (match($0,/your regexp/,m)) print m[0] }

match (string, regexp [, array]) Dizi mevcutsa temizlenir ve ardından dizinin sıfırıncı öğesi, regexp ile eşleşen dizenin tüm kısmına ayarlanır. Regexp parantez içeriyorsa, dizinin tamsayı dizinli öğeleri, dizgenin karşılık gelen parantezli alt ifade ile eşleşen kısmını içerecek şekilde ayarlanır. http://www.gnu.org/software/gawk/manual/gawk.html#String-Functions


13

Girilecek son satırında sadece ilgilenen ve yalnızca bir eşleşme (bir kabuk komutunun özeti hattının örneğin bir parçası) bulmak için beklemek, ayrıca gelen benimsenen bu çok kompakt kodu, deneyebilirsiniz regexp'in eşleşmeleri yazdırmak için nasıl "awk" kullanarak? :

$ echo "xxx yyy zzz" | awk '{match($0,"yyy",a)}END{print a[0]}'
yyy

Veya kısmi sonucu olan daha karmaşık versiyon:

$ echo "xxx=a yyy=b zzz=c" | awk '{match($0,"yyy=([^ ]+)",a)}END{print a[1]}'
b

Uyarı: awk match()üç bağımsız değişkeni olan işlev yalnızca içinde bulunur gawk,mawk

İşte kullanarak başka güzel çözümdür olan ileriye dönük regex içinde grepyerine awk. Bu çözüm, kurulumunuz için daha düşük gereksinimlere sahiptir:

$ echo "xxx=a yyy=b zzz=c" | grep -Po '(?<=yyy=)[^ ]+'
b

Neden "tail -n1" eklediniz? Bu onsuz iyi çalışmalı, değil mi?
Arthur Accioly

1
@ArthurAccioly Doğru. Bir ping çağrısından ortalama gidiş dönüş süresini çıkarmak için bu terimi kullandım, geldiği yer orası. onu keşfetmenin 4 yıl
Daniel Alder

12

Perl bir seçenekse, şunu deneyebilirsiniz:

perl -lne 'print $1 if /(regex)/' file

Büyük / küçük harfe duyarlı olmayan eşlemeyi uygulamak için ideğiştiriciyi ekleyin

perl -lne 'print $1 if /(regex)/i' file

Maçtan SONRA her şeyi yazdırmak için:

perl -lne 'if ($found){print} else{if (/regex(.*)/){print $1; $found++}}' textfile

Maçı ve maçtan sonraki her şeyi yazdırmak için:

perl -lne 'if ($found){print} else{if (/(regex.*)/){print $1; $found++}}' textfile

3

Bu durumda sed kullanmak da şık olabilir. Örnek (satırı, satırdaki eşleşen "yyy" grubuyla değiştirin):

$ cat testfile
xxx yyy zzz
yyy xxx zzz
$ cat testfile | sed -r 's#^.*(yyy).*$#\1#g'
yyy
yyy

İlgili kılavuz sayfası: https://www.gnu.org/software/sed/manual/sed.html#Back_002dreferences-and-Subexpressions


Gnu sed olmayanlar için çözüm sed -n 's/^.*\(yyy\).*$/\1/gp' < testfile
şuna

1
@GrigoryEntin - bsd sed orijinal cevapla iyi çalışıyor. POSIX tarafından desteklenen genişletilmiş regex anahtarı -E'dir, ancak FreeBSD'de en az -r -E ile aynıdır (2010'da eklenen -r). Her neyse, -E ile dene (4.3'te gnu sed eklendi -E)
Juan

3

Konu dışında, bu grep kullanılarak da yapılabilir, sadece herhangi birinin grep çözümü araması durumunda buraya gönderebilirsiniz.

echo 'xxx yyy zzze ' | grep -oE 'yyy'

Normal ifadeyle bile yakalamanın basit yolu. Tam olarak ihtiyacım olan şey. Teşekkürler!
Seçim Çerçevesi

Bu benim için çalışıyor; Benim durumum şuna benzer: echo "web_port = 8080, shutdown_port = 8005" | grep -oE "web_port = [0-9] +" # return 8080
Robb Tsang

0

Aradığınız metnin / kalıbın (örneğin "yyy") hangi sütunda olduğunu biliyorsanız, o sütuna uyup uymadığını kontrol edebilir ve yazdırabilirsiniz.

Örneğin, aşağıdaki içeriğe sahip bir dosya verildiğinde ( asdf.txt olarak adlandırılır )

xxx yyy zzz

ikinci sütunu yalnızca "yyy" kalıbıyla eşleşiyorsa yazdırmak için, şöyle bir şey yapabilirsiniz:

awk '$2 ~ /yyy/ {print $2}' asdf.txt

Bunun aynı zamanda, aşağıdaki gibi, ikinci sütunun içinde "yyy" bulunan herhangi bir satırla da eşleşeceğini unutmayın:

xxx yyyz zzz
xxx zyyyz
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.