Grep Maç ve özü


10

Gibi satırları içeren bir dosya var

proto=tcp/http  sent=144        rcvd=52 spkt=3 
proto=tcp/https  sent=145        rcvd=52 spkt=3
proto=udp/dns  sent=144        rcvd=52 spkt=3

Ben ise proto değerini ayıklamak gerekir tcp/http, tcp/https, udp/dns.

Şimdiye kadar bunu denedim grep -o 'proto=[^/]*/'ama sadece değeri ayıklayabiliyorum proto=tcp/.



Bu işidir sed, awkya perldeğildir grep.
OrangeDog

Yanıtlar:


1

Bunun bir önceki sorunuzla ilgili olduğunu varsayarsak , yanlış yolda ilerlersiniz. Çoğu zaman istediğini yapacak türden bitleri bir araya getirmeye çalışmak yerine ve en ufak bir şey yapmak istediğiniz her seferinde tamamen farklı bir komut dosyası almanız gerekecek, sadece ayrıştırabileceğiniz 1 komut dosyası oluşturun girdi dosyalarınızı f[]alan adlarınızı (etiketler) değerleriyle eşleyen bir diziye ( aşağıda) ve sonuçla ne istersen yapabilirsiniz, örneğin önceki sorunuzdan bu girdi dosyası verilmişse:

$ cat file
Feb             3       0:18:51 17.1.1.1                      id=firewall     sn=qasasdasd "time=""2018-02-03"     22:47:55        "UTC""" fw=111.111.111.111       pri=6    c=2644        m=88    "msg=""Connection"      "Opened"""      app=2   n=2437       src=12.1.1.11:49894:X0       dst=4.2.2.2:53:X1       dstMac=42:16:1b:af:8e:e1        proto=udp/dns   sent=83 "rule=""5"      "(LAN->WAN)"""

adlarına / etiketlerine göre dizine eklenmiş bir değer dizisi oluşturan bir awk betiği yazabiliriz:

$ cat tst.awk
{
    f["hdDate"] = $1 " " $2
    f["hdTime"] = $3
    f["hdIp"]   = $4
    sub(/^([^[:space:]]+[[:space:]]+){4}/,"")

    while ( match($0,/[^[:space:]]+="?/) ) {
        if ( tag != "" ) {
            val = substr($0,1,RSTART-1)
            gsub(/^[[:space:]]+|("")?[[:space:]]*$/,"",val)
            f[tag] = val
        }

        tag = substr($0,RSTART,RLENGTH-1)
        gsub(/^"|="?$/,"",tag)

        $0 = substr($0,RSTART+RLENGTH)
    }

    val = $0
    gsub(/^[[:space:]]+|("")?[[:space:]]*$/,"",val)
    f[tag] = val
}

ve verilerinizle istediğiniz her şeyi yapabileceğinizi göz önünde bulundurarak, alan adlarına referans vererek, örneğin -ebir komut dosyasını bir komut satırı komut dosyasıyla karıştırmak için GNU awk kullanmak gibi :

$ awk -f tst.awk -e '{for (tag in f) printf "f[%s]=%s\n", tag, f[tag]}' file
f[fw]=111.111.111.111
f[dst]=4.2.2.2:53:X1
f[sn]=qasasdasd
f[hdTime]=0:18:51
f[sent]=83
f[m]=88
f[hdDate]=Feb 3
f[n]=2437
f[app]=2
f[hdIp]=17.1.1.1
f[src]=12.1.1.11:49894:X0
f[c]=2644
f[dstMac]=42:16:1b:af:8e:e1
f[msg]="Connection"      "Opened"
f[rule]="5"      "(LAN->WAN)"
f[proto]=udp/dns
f[id]=firewall
f[time]="2018-02-03"     22:47:55        "UTC"
f[pri]=6

$ awk -f tst.awk -e '{print f["proto"]}' file
udp/dns

$ awk -f tst.awk -e 'f["proto"] ~ /udp/ {print f["sent"], f["src"]}' file
83 12.1.1.11:49894:X0

2
Bu harika, çok teşekkür ederim soo :)
user356831

Bu tür bir iş perliçin kullanımı daha kolay olabilir.
OrangeDog

1
@OrangeDog neden bunu düşünüyorsun? Aslında böyle bir cevap yayınlamak sakıncası yoksa perl eşdeğerini görmek istiyorum. Perl, kutumda yoksa ve yükleyemezsem kesinlikle daha kolay olmayacak, ancak bu, yıllar boyunca sık sık uğraştığım bir şeydi. Awk ise zorunlu bir yardımcı programdır ve bu nedenle sed, grep, sort, vb.Gibi UNIX kurulumlarında her zaman mevcuttur
Ed Morton

@EdMorton true, ancak kişisel olarak perl'in varsayılan olarak dahil olmadığı bir dağıtımla karşılaşmadım. Karmaşık awkve sedkomut dosyaları genellikle daha basittir, perlçünkü ortak görevler için ek özelliklerle aslında bunların bir üst kümesidir.
OrangeDog

@OrangeDog hiç kimse daha karmaşık bir sed komut dosyası yazmamalı s/old/new/gve sed awk değil bu yüzden bunu bir kenara bırakalım . Ben tamamen karmaşık awk komut dosyalarının perl içinde daha basit olduğunu kabul etmiyorum. Elbette daha kısa olabilirler, ancak kısalık, yazılımın arzu edilen bir özelliği değildir, özlüdür ve gerçek bir yararı olması son derece nadirdir ve genellikle okumak çok daha zordur, bu yüzden insanlar zoitz.com gibi şeyler yayınlarlar / archives / 13 perl ile ilgili ve awk'den farklı olarak salt yazılan bir dil olarak adlandırılıyor. Yine de buna eşdeğer bir perl görmek istiyorum
Ed Morton

13

İle grep -o, ayıklamak istediğinizle tam olarak eşleşmeniz gerekir. Dizeyi ayıklamak istemediğiniz için proto=dizeyle eşleşmemelisiniz.

Bir eğik çizgi ve bazı boş olmayan alfasayısal dizeyle eşleşecek tcpveya udpbunları izleyecek genişletilmiş normal bir ifade

(tcp|udp)/[[:alnum:]]+

Bunu verilerinize uygulama:

$ grep -E -o '(tcp|udp)/[[:alnum:]]+' file
tcp/http
tcp/https
udp/dns

Bunu yalnızca dizeyle başlayan satırlarda yaptığımızdan emin olmak için proto=:

grep '^proto=' file | grep -E -o '(tcp|udp)/[[:alnum:]]+'

İle sed, =ilk boş karakterden önce ve ilk boş karakterden sonra her şeyi kaldırmak :

$ sed 's/^[^=]*=//; s/[[:blank:]].*//' file
tcp/http
tcp/https
udp/dns

Bunu yalnızca dizeyle başlayan satırlarda yaptığımızdan emin olmak için yukarıdaki proto=ile aynı ön işleme adımını ekleyebilir grepveya

sed -n '/^proto=/{ s/^[^=]*=//; s/[[:blank:]].*//; p; }' file

Burada, varsayılan çıktıyı -nseçenekle bastırırız ve sonra ikameleri ve satırın açık bir baskısını yalnızca çizgi eşleşirse tetikleriz^proto= .


İle awk, varsayılan alan ayırıcısını kullanarak ve ardından ilk alanı bölüp =ikinci bitini yazdırın:

$ awk '{ split($1, a, "="); print a[2] }' file
tcp/http
tcp/https
udp/dns

Bunu yalnızca dizeyle başlayan satırlarda yaptığımızdan emin olmak için yukarıdaki proto=ile aynı ön işleme adımını ekleyebilir grepveya

awk '/^proto=/ { split($1, a, "="); print a[2] }' file

10

GNU grep kullanıyorsanız ( -Pseçenek için) şunları kullanabilirsiniz:

$ grep -oP 'proto=\K[^ ]*' file
tcp/http
tcp/https
udp/dns

Burada proto=, doğru sütunu çıkardığımızdan emin olmak için dizeyi eşleştiriyoruz , ancak daha sonra\K bayrakla çıkarıyoruz.

Yukarıdaki sütunların boşlukla ayrılmış olduğunu varsayar. Sekmeler de geçerli bir ayırıcıysa, \Sboşluk olmayan karakterlerle eşleşmek için kullanılır , böylece komut şöyle olur:

grep -oP 'proto=\K\S*' file

Ayrıca proto=, a gibi bir alt dizenin olduğu eşleşme alanlarına karşı da korumak istiyorsanız thisisnotaproto=tcp/https, aşağıdaki şekilde kelime sınırı ekleyebilirsiniz \b:

grep -oP '\bproto=\K\S*' file

1
Bunu sadece yazarak geliştirebilirsiniz grep -oP 'proto=\K\S+'. proto=tcp/httpYerine boşluk bir sekme tarafından takip edilebilir ve \Sfarklı [^ ]olmayan herhangi bir boşluk karakteri ile eşleşir.
Mosvy

@mosvy: Bu iyi bir öneri, teşekkürler.
user000001

1
Her neyse, -oaynı zamanda bir GNUizm. -Pyalnızca grepPCRE desteği ile oluşturulmuşsa GNU tarafından desteklenir (oluşturma zamanında isteğe bağlıdır).
Stéphane Chazelas

6

Kullanma awk:

awk '$1 ~ "proto" { sub(/proto=/, ""); print $1 }' input

$1 ~ "proto" yalnızca aşağıdaki satırlarda işlem yapmamızı sağlar proto ilk sütundaki

sub(/proto=/, "")proto=girişten kaldırılacak

print $1 kalan sütunu yazdırır


$ awk '$1 ~ "proto" { sub(/proto=/, ""); print $1 }' input
tcp/http
tcp/https
udp/dns

3

Kod golf grepçözümleri üzerinde

grep -Po "..p/[^ ]+" file

ya da

grep -Po "..p/\S+" file

3

cutKomutunu kullanarak :

cut -b 7-15 foo.txt

3
Bu, httpve dnssatırlarındaki sondaki boşlukları içerecektir .
G-Man

2

Başka bir grepçözüm:

grep -o '[^=/]\+/[^ ]\+' file

Ve sedsadece eşleşen yakalanan grubu basan benzer bir grup:

sed -n 's/.*=\([^/]\+\/[^ ]\+\).*/\1/p' file

1

Başka bir awkyaklaşım:

$ awk -F'[= ]' '/=(tc|ud)p/{print $2}' file
tcp/http
tcp/https
udp/dns

Bu awk alan ayırıcısını =ya bir boşluğa ya da bir boşluğa ayarlar . Ardından, çizgi a ile eşleşiyorsa =, udveyatc bir takipp , ikinci alanı yazdırın.

Başka bir sedyaklaşım (tüm sürümleri için taşınabilir değildir sed, ancak GNU ile çalışır sed):

$ sed -En 's/^proto=(\S+).*/\1/p' file 
tcp/http
tcp/https
udp/dns

-nVasıta "yazdırmak değil" ve -Ebize vermek genişletilmiş düzenli ifadeler sağlar \S, "non-boşluk" için +"bir veya daha fazla" ve yakalanması için parantez için. Sonunda,/p sonunda işlem sadece başarılı olursa ikame operatörü için bir eşleşme varsa sed print yapacak.

Ve perl biri:

$ perl -nle '/^proto=(\S+)/ && print $1' file 
tcp/http
tcp/https
udp/dns

-nVasıta "çizgi ile girdi dosyası satır okumak ve verdiği komut uygulamak -eher bir satırın". -lHer bir yeni satır ekler printçağrısı (ve giriş çıkan yeni satır kaldırır). Komut dosyasının kendisi, bir boşluktan sonra bulunan boşluk olmayan karakterlerin en uzun kısmını yazdırır.proto= .


1
-Egiderek daha taşınabilir hale geliyor, ama \Sdeğil. [^[:space:]]daha taşınabilir bir eşdeğerdir.
Stéphane Chazelas

1

İşte oldukça kolay başka bir çözüm:

grep -o "[tc,ud]*p\\/.*  "   INPUTFile.txt  |   awk '{print $1}'

Senin grephiçbir şeyle uyuşmuyor. bir ya da ya da ya da ya da bir değişmez karakterin, ardından a ve ters eğik çizginin bir örneğini [tc,ud]\*\\/.*arar . Muhtemelen demek istedin . Eğer awk kullanıyorsanız Ama sonra, siz de awk içinde her şey olabilir: . tc,ud*pgrep -Eo '(tc|ud)p/.* ' file | awk '{print $1}'awk -F'[= ]' '/(tc|ud)p/{print $2}' file
terdon

Birisi orijinalimi değiştirdi, yıldızdan önce fazladan bir Ters Eğik Çizgi vardı, Sir'i kaldırdım.
mkzia

Düzenlediğiniz için teşekkürler, ancak bunun sadece şans eseri çalıştığından korkuyorum. Daha önce açıklandığı gibi, [tc,ud]pvasıta "biri t, c, ,, uveya dbir takip pÇünkü sadece burada maçları Yani. tcpSahiptir cpve udpsahip dp. Ama aynı zamanda eşleşir ,pveya tpvb Ayrıca, şimdi sahip olduğu *, bu maç olacak ppp(aynı zamanda *vasıta "0 veya daha fazla" eşleşmiyor bile o) eşleşir böylece (bir karakter sınıfını istemiyoruz. [ ]), ne istediğiniz bir gruptur: (tc|ud)ile (kullanım -Ebayrağı grep.) Ayrıca, .*yapar tüm çizgi maç
terdon

1
@Jesse_b: mkzia teknik olarak bir “Yeni katkıda bulunan” olmasa da, komutları için kod biçimlendirmesi kullanmadığı gerçeği ile deneyimsiz bir kullanıcıdır. Yine de, italik işaretleme olarak değil, komutlarında \*ilkini almak için yazmak için yeterince akıllıydılar *. Komutu kod biçimine koyduğunuzda, \önce *görünmesine neden oldunuz (böylece komutun başarısız olmasına neden oluyorsunuz ). Başkalarının yayınlarını düzenlerken, lütfen yayının görünümünü bu şekilde değiştirdiğine dikkat edin.
G-Man, 'Monica'yı Yeniden Başlat' dedi

@terdon: (1) Hayır, aslında eşleşmiyor ppp. Tabii ki bunu eşleşecek doğru olduğunu konum ,pveya  tp- veya uucp, ttp, cutp, ductpveya d,up.
G-Man, 'Monica'yı Yeniden Başlat' dedi


0
cat file| cut -f1 -d' '| cut -f2 -d'='
tcp/http
tcp/https
udp/dns

kesim seçenekleri:

  • -f - alan
  • -d - sınırlayıcı
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.