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.