Awk içinde birden fazla sınırlayıcı kullanma


203

Aşağıdaki satırları içeren bir dosya var:

/logs/tc0001/tomcat/tomcat7.1/conf/catalina.properties:app.env.server.name = demo.example.com
/logs/tc0001/tomcat/tomcat7.2/conf/catalina.properties:app.env.server.name = quest.example.com
/logs/tc0001/tomcat/tomcat7.5/conf/catalina.properties:app.env.server.name = www.example.com

Yukarıdaki çıktıda 3 alan çıkarmak istiyorum (Sayı 2, 4 ve sonuncusu *.example.com). Aşağıdaki çıktı alıyorum:

cat file | awk -F'/' '{print $3 "\t" $5}'
tc0001   tomcat7.1
tc0001   tomcat7.2
tc0001   tomcat7.5

Son alan adını alan adıyla da nasıl ayıklayabilirim '='? multiple delimiterAlanı ayıklamak için nasıl kullanabilirim ?


2
Aynı ama farklı awkolan sorumu cevaplamak için boş olduklarında tarlaları yutuyorlardı ve bu da alan numaralandırmasını engelledi. Değiştim -F " "için -F "[ ]"ve awkartık boş alanları yutmak vermedi.
— Adam

Yanıtlar:


326

Sınırlayıcı düzenli bir ifade olabilir.

awk -F'[/=]' '{print $3 "\t" $5 "\t" $8}' file

üretir:

tc0001   tomcat7.1    demo.example.com  
tc0001   tomcat7.2    quest.example.com  
tc0001   tomcat7.5    www.example.com

42
Tabii ki, catişlem gerekli değildir: awk '...' file. Ayrıca, çıktı alanı ayırıcı kullanmak daha düzenli olurdu:awk -F'[/=]' -v OFS="\t" '{print $3, $5, $8}'
— glenn jackman

17
Awk sınırlayıcıları düzenli ifadeler olabilir ... bu benim günümü yaptı!
— das.cyklone

4
@ das.cyklone: ​​awk ayrıca birkaç ayırıcıya sahip olabilir |: ex: awk -F 'this|that|[=/]' '......' (bir şeyleri ayıran sözcükler / dizeler için yararlıdır) (bunun 2 ayırıcı arasındaki alanlardaki boşlukları sakladığını unutmayın. Ekleme de |[ \t]+yararlı olabilir, ancak bir şeyler yapabilir zor ... 'bu' öncesi ve sonrasında genellikle boşluklar olduğu için, bu boşluk (lar) ve 'bu' arasında 2 ekstra boş alan görünmesini sağlar)
— Olivier Dulac

Ben 2 farklı dağıtım üzerinde denedim ve aynı davranışı elde: Ben netstat -ntpl "netstat -ntpl | sed 's /: / /' | awk '{print $ 5}'" bağlantı noktasından almak istiyorum ama doulbe borulama olmadan yapabilirdi Bu işe yarar ama alan 17'deki verileri beklemiyordum: "netstat -ntpl | awk -F" |: "'{print $ 17}' '
— louigi600

2
evet ... bu istediğimi elde etti: awk -F "[:] +" '/ \ / postmaster * $ / {print $ 5}'
— louigi600

44

İyi haberler! awkalan ayırıcı normal bir ifade olabilir. Sadece kullanmanız gerekir -F"<separator1>|<separator2>|...":

awk -F"/|=" -vOFS='\t' '{print $3, $5, $NF}' file

İadeler:

tc0001  tomcat7.1  demo.example.com
tc0001  tomcat7.2  quest.example.com
tc0001  tomcat7.5  www.example.com

Buraya:

  • -F"/|="birine giriş alanı ayırıcısını ayarlar /veya =. Ardından, çıkış alanı ayırıcısını bir sekmeye ayarlar.

  • -vOFS='\t'-vbir değişkeni ayarlamak için bayrağı kullanıyor . OFSÇıktı Alanı Ayırıcı için varsayılan değişkendir ve sekme karakterine ayarlanır. Bayrak gereklidir, çünkü OFS gibi yerleşik değildir -F.

  • {print $3, $5, $NF} 3., 5. ve son alanları giriş alanı ayırıcısına göre yazdırır.


Başka bir örneğe bakın:

$ cat file
hello#how_are_you
i#am_very#well_thank#you

Bu dosyanın iki alan ayırıcısı vardır #ve _. Ayırıcının biri veya diğeri ne olursa olsun ikinci alanı yazdırmak istiyorsak, ikisini de ayırıcı yapalım!

$ awk -F"#|_" '{print $2}' file
how
am

Dosyalar aşağıdaki gibi numaralandırılır:

hello#how_are_you           i#am_very#well_thank#you
^^^^^ ^^^ ^^^ ^^^           ^ ^^ ^^^^ ^^^^ ^^^^^ ^^^
  1    2   3   4            1  2   3    4    5    6

1
Düzenlemeniz için @BUFU'ya teşekkürler. Sadece FS kısmına odaklanmak için OFS referansını kaldırdım, ancak buna sahip olmak da iyi. Şerefe!
— fedorqui 'SO' zarar vermeyi durdur '29

5

Boşluğunuz tutarlıysa bunu sınırlayıcı olarak kullanabilirsiniz, ayrıca \tdoğrudan eklemek yerine , çıkış ayırıcısını ayarlayabilirsiniz ve otomatik olarak dahil edilir:

< file awk -v OFS='\t' -v FS='[/ ]' '{print $3, $5, $NF}'

3

Bir alan herhangi bir sayı ayırıcı için 2yoluyla 5veya mektup aveya #ayırma karakter, örneğin en az 2 kat ve en fazla 6 kez, tekrarlanır ve bir boşluk:

awk -F'[2-5a# ]{2,6}' ...

Eminim bu varyasyonlar () ve parametreleri kullanarak var


3

Perl tek katmanlı:

perl -F'/[\/=]/' -lane 'print "$F[2]\t$F[4]\t$F[7]"' file

Bu komut satırı seçenekleri kullanılır:

  • -ngiriş dosyasının her satırı etrafında döngü, satırı $_değişkene koyun, her satırı otomatik olarak yazdırmayın

  • -l işlemeden önce yeni satırları kaldırır ve daha sonra tekrar ekler

  • -aotomatik bölme modu - perl otomatik olarak giriş satırlarını @Fdiziye böler . Boşlukta bölme varsayılanları

  • -Fautosplit değiştirici, bu örnekte /ya=

  • -e perl kodunu çalıştır

Perl awk ile yakından ilişkilidir, ancak @Fautosplit dizisi indekste $F[0]başlarken awk alanları 1 $ ile başlar.


2

Diğeri ise -F seçeneğini kullanmak ancak metni sol ve sağ parantez arasına yazdırmak için normal ifadeyi iletmektir ().

Dosya içeriği:

528(smbw)
529(smbt)
530(smbn)
10115(smbs)

Komuta:

awk -F"[()]" '{print $2}' filename

sonuç:

smbw
smbt
smbn
smbs

Yalnızca arasındaki metni yazdırmak için awk kullanma []:

Kullanın awk -F'[][]' ama awk -F'[[]]'çalışmayacak.

http://stanlo45.blogspot.com/2020/06/awk-multiple-field-separators.html


Cevabınız silme kuyruğunda geldi, çünkü 10 üzerinden 9 kez, kendi bloglarına bağlanan 1 şöhrete sahip kullanıcılar genellikle spam'dir. Ama sizinkiler kuralın istisnasıdır. İçeriğin son 10 yılında bir altın madeni var, umarım onu ​​ölümsüzleştirmek için bir planınız vardır.
— Eric Leschinski

0

Tahtada birçok mükemmel cevap görüyorum, ancak yine de kod parçamı yüklemek istiyorum,

awk -F"/" '{print $3 " " $5 " " $7}' sam | sed 's/ cat.* =//g'


2
print $3 " " $5 " " $7gibi yazdırılabilir print $3, $5, $7. Ayrıca, awk kullanmanın ve sonra sed için boru kullanmanın avantajını görmüyorum. Genel olarak awk yeterli olabilir ve diğerleri bunu gösterir.
— fedorqui 'SO' zarar vermeyi durdurun
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.