Awk / pattern / {print “text”} / patern / {print “”} kullanıldığında bir ELSE modeli var mı?


22

Diyelim ki benim gibi metin dosyası var:

R1 12 324 3453 36 457 4 7 8
R2 34 2342 2525 25 25 26 26 2 2
R3 23 2342 32 52 54 543 643 63
R4 25 234 2342 4 234242

awkBu satırları farklı işlemek için kullanmak istiyorum.

awk '/R1/ { print "=>" $0} /R2/ { print "*" $0} '

ve tüm satırları olduğu gibi (önceden işlediğim satırların kopyalarını yapmadan) olduğu gibi yazdırmak istiyorum, temelde satırımın /ELSE/ { print $0}sonuna ihtiyacım var awk.

Böyle bir şey var mı?

Yanıtlar:


27

Basitleştirilmiş Yaklaşım awk

awk '/R1/ {print "=>" $0;next} /R2/{print "*" $0;next} 1' text.file

[jaypal:~/Temp] cat text.file 
R1 12 324 3453 36 457 4 7 8
R2 34 2342 2525 25 25 26 26 2 2
R3 23 2342 32 52 54 543 643 63
R4 25 234 2342 4 234242

[jaypal:~/Temp] awk '/R1/ { print "=>" $0;next} /R2/{print "*" $0;next}1' text.file
=>R1 12 324 3453 36 457 4 7 8
*R2 34 2342 2525 25 25 26 26 2 2
R3 23 2342 32 52 54 543 643 63
R4 25 234 2342 4 234242
[jaypal:~/Temp] 

Örüntü Dağılımı {Eylem} İfadeleri:

  • /R1/ { print "=>" $0;next}: Bu /R1/, baskıya etki eden çizgilerin yapılacağı anlamına gelir =>. nextawk ifadelerinin geri kalanının yok sayılacağı ve bir sonraki satıra bakılacağı anlamına gelir.

  • /R2/{print "*" $0;next}: Bu pattern /R2/, yazdırma eylemiyle eşleşen satırların gerçekleştirileceği anlamına gelir *. Ne zaman awkbaşlar işleme, ilk pattern {action}olarak ifadesi dikkate alınmayacaktır pattern /R1/sahip hatlar için doğru olmayacaktır /R2/. Böylece ikinci pattern {action}açıklama hattında yapılacak. nexttekrar daha fazla işlem yapmak istemediğimiz ve awkusulüne göre bir sonraki satıra geçeceğimiz anlamına gelir .

  • 1tüm satırları yazdırır. Sadece bir koşul hayır ile sağlandığında {action}, awk varsayılanları kullanır {print}. Burada şart, 1doğru olarak yorumlanır, bu yüzden her zaman başarılı olur. Bu noktaya gelirsek, bunun nedeni ilk ve ikinci pattern {action}ifadelerin yok sayılması ya da by-pass edilmesidir (içermeyen satırlar için /R1/ve /R2/), bu nedenle kalan satırlar için varsayılan yazdırma işlemi yapılacaktır.


Marjinal olarak yayınlanan tüm çözümlerden en hızlı şekilde çalıştığı görülüyor.
Chris Down

1
Sözdizimsel şekerin burada doğru terim olduğundan emin değilim ... Bu sadece sözdizimi.
Daniel Hershcovich

7

awkOlağan şartlara gelince olağan şüphelileri uygular. Eşleşmek istediğiniz iş printfyerine kullanmak iyi bir fikirdir print.

awk '{ if (/^R1/) { printf("=> %s\n", $0) } else if (/^R2/) { printf("* %s\n", $0) } else { print $0 } }'

Buna gerçekten ihtiyacın yok if-then-else.
jaypal singh

1
Bu mükemmel çalışıyor olsa da, aptalca değil. Bilinçli kullanımını nextawk programing bir önemli bir araçtır.
dmckee

2
printfBurada kullanmanın anlamını anlamıyorum . Tek avantajı (birleştirmeden ziyade daha şık formatlama yapmadığınız sürece) burada ilgili olmayan yeni bir satır eklememesidir.
Gilles 'SO- kötülük' dur 'kas

1
Bu, sezgisel ve şaşırtıcı bir sonuçtur. Unadorned printyalnızca çıktı $0alırken printf, format dizesini ayrıştırmak zorunda kalır.
jw013

5

Chris Down zaten bir bloktaki ifadeyi açık 'if' ifadesini kullanarak regexps için başka bir yoldan nasıl alabileceğinizi gösterdi. Çözümü muhtemelen daha iyi olmasına rağmen, aynı etkiyi başka yollardan da alabilirsiniz.

Birincisi, sadece diğerleri tarafından eşleştirilmeyen metinlerle eşleşecek üçüncü bir regex yazmak, sizin durumunuzda, bu şöyle görünür:

awk '/^R1/ { print "=>" $0}
     /^R2/ { print "*" $0}
     /^[^R]/ || /^R[^12]/ { print $0 } '

Not: bu, sabitlenmiş regexps kullanır - regexps'in başında ^ yalnızca bir satırın başında eşleşir - orijinal desenleriniz bunu yapmadı; bu, eşleştirmeyi bir satırdaki tüm karakterleri kontrol etmek yerine hafifçe yavaşlatır. sonraki satıra kadar atlama. Üçüncü ("else") durumu, 'R' ([^ R]) olmayan bir karakterle başlayan veya 'R' ile başlayan ve ardından '1' veya 'olmayan bir karakterle başlayan bir çizgiyle eşleşir. 2 '(R [^ 12]). ^ 'Nin iki farklı anlamı biraz kafa karıştırıcıdır, ancak bu hata uzun zaman önce yapıldı ve yakın zamanda değişmeyecek.

Tamamlayıcı regexps kullanmak için, gerçekten bağlanması gerekir, aksi takdirde [^ R] örneğin 1'i eşleştirir. Sizin gibi çok basit regexps için bu yaklaşım faydalı olabilir, ancak regexps daha karmaşık hale geldikçe, bu yaklaşım yönetilemez hale gelecektir. Bunun yerine, her satır için durum değişkenlerini kullanabilirsiniz, bunun gibi:

awk '{ handled = 0 }
     /^R1/ { print "=>" $0; handled = 1}
     /^R2/ { print "*" $0; handled = 1}
     { if (!handled) print $0 } '

Bu ayarlar, her yeni satır için sıfıra, ardından iki regexps'den biriyle eşleşirse 1'e işlenir ve son olarak hala sıfırsa, $ 0 yazdırmasını gerçekleştirir.


Büyük dosyalarda her ikisinin de ( burada gösterildiği gibi ) koşullu kullanmaktan daha az etkili olduğuna dikkat edilmelidir . rfiletekrarlanan sorgulayıcı veri kümesinin sadece 10000 satırıdır.
Chris Down

4
if (!handled)Yuck! nextDiğer eylemleri göz önünde bulundurmayı durdurmak için kullanın .
dmckee

İçin +1 if (!handled). Genel, esnek, yeniden kullanılabilir çözümler iyidir. Ya bu soruyu soran bir sonraki kişi, baskıdan sonra daha fazla işlem yapmak isterse? İle cevaplar nextbunu desteklemiyor.
Scott
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.