4 puan yazan GN⁺ 2023-08-29 | 1 yorum | WhatsApp'ta paylaş
  • GNU awk, stdin ve dosyalar üzerinde otomatik olarak dolaşır; filtreleme·yerine koyma·alan işleme işlemlerini tek satırlık komutlarla birleştirerek CLI metin işlerini yürütür
  • /regexp/ ve !/regexp/, mevcut giriş satırını denetleyen kısaltılmış sözdizimleridir; koşul doğruysa varsayılan olarak $0 yazdırılır
  • sub yalnızca ilk eşleşmeyi, gsub ise tüm eşleşmeleri değiştirir; hedef belirtilmezse yerine koyma geçerli giriş satırı $0 üzerine uygulanır
  • Boşluk tabanlı alan ayırma ve $N, NF, $NF sayesinde awk, belirli sütunları seçmek veya koşul uygulamak gibi alan tabanlı işler için çok uygundur
  • cond{action} parçalarını art arda yazar ve BEGIN{}·END{} eklerseniz, basit filtrelerin ötesine geçen; string, sayı ve ilişkisel dizileri de içeren küçük programlar yazabilirsiniz

awk'ın çalışma biçimi

  • awk, grep ve sed gibi metni filtreleyebilir; ayrıca daha karmaşık işlemler için programlama özellikleri de sunar
  • Girdi stdin veya dosyalardan alınabilir ve varsayılan olarak satır satır dolaşılarak koşullar ile işlemler uygulanır
  • Giriş satırının tamamına özel değişken $0 ile erişilir
    • Doğru terim input record olsa da, bu bölümde açıklama satır düzeyinde ele alınır

Filtreleme ve varsayılan çıktı

  • Düzenli ifadeler /.../ biçiminde yazılır; bir string'in düzenli ifadeyle eşleşip eşleşmediğini denetlemek için string ~ /regexp/ sözdizimi kullanılır
  • Ters koşul string !~ /regexp/ ile ifade edilir
  • Denetlenecek string belirtilmezse hedef $0 olur
  • Yalnızca koşul varsa ve işlem yoksa, koşul doğru olduğunda $0 otomatik olarak yazdırılır
    • awk '/regexp/', awk '$0 ~ /regexp/{print $0}' ifadesinin kısaltılmış halidir
    • awk '!/regexp/', awk '$0 !~ /regexp/{print $0}' ifadesinin kısaltılmış halidir
  • Örneklerde at içeren satırların yazdırılması veya e içermeyen satırların seçilmesiyle temel filtreleme akışı gösterilir

1 kullanarak deyimsel çıktı

  • Koşul ifadelerinde sıfır olmayan sayılar ve boş olmayan string'ler doğru kabul edilir
  • awk '1', tüm giriş satırları için her zaman doğru olan bir koşul veren deyimsel bir kullanımdır
  • İşlem olmadığında doğru koşul $0 çıktısına yol açtığı için awk '1' tüm girdiyi olduğu gibi yazdırır
  • Sonuç, awk '{print $0}' ya da basitçe cat ile aynıdır

Yerine koyma: sub ve gsub

  • awk, arama ve yerine koyma için sub ve gsub işlevlerini sunar
  • sub(/:/, "-"), her giriş satırında yalnızca ilk : karakterini - ile değiştirir
  • gsub(/:/, "-"), her giriş satırındaki tüm : karakterlerini - ile değiştirir
  • Her iki işlev de ilk argüman olarak eşleşecek düzenli ifadeyi, ikinci argüman olarak ise yerine koyma string'ini alır
  • Girdi string'i ayrıca verilmezse varsayılan hedef $0 olur
  • Yerine koyma başarılı olursa hedef girdi değiştirilir
  • Yerine koyma bloğundan sonraki 1, blok dışındaki bir koşul ifadesi olarak yorumlanır ve değiştirilmiş $0 değerinin yeniden yazdırılmasını sağlar
    • awk '{sub(/:/, "-")} 1', awk '{sub(/:/, "-"); print $0}' ile aynı sonucu verir
    • Yalnızca print yazılsa bile varsayılan çıktı hedefi $0'dır

grep, sed, awk arasında seçim ölçütleri

  • Basit satır filtrelemede, bu iş için optimize edilmiş grep, sed veya awk'tan daha hızlı olabilir
  • Yerine koyma işlerinde sed, awk'tan daha hızlı olabilir
  • Araçlar arasındaki özellikler her zaman bire bir örtüşmez
    • grep -o işlevini sed veya awk ile gerçekleştirmek için daha fazla adım gerekebilir
    • Özyinelemeli arama yalnızca grep tarafından sağlanır
  • İlgili tartışmayı unix.stackexchange: When to use grep, sed, awk, perl, etc bağlantısında görebilirsiniz

Alan tabanlı işleme

  • awk, özellikle alan tabanlı işleme için sık kullanılır
  • Varsayılan olarak giriş satırını boşluklara göre böler ve her alana $N ile erişilir
    • $2 ikinci alandır
    • $NF son alandır
    • NF, geçerli giriş satırındaki toplam alan sayısıdır
  • table.txt örneği, sütun düzeyindeki işlemleri özlü biçimde gösterir
    • Her satırın ikinci alanını yazdırma
    • Yalnızca son alanı negatif olan satırları yazdırma
    • Sadece birinci alanda b karakterini B olarak değiştirme
  • Örnek dosyalar example_files dizininde bulunur

Tek satırlık komut yapısı

  • Genel bir awk tek satırlık komutu şu biçimdedir
awk 'cond1{action1} cond2{action2} ... condN{actionN}'
  • Koşul yoksa işlem her zaman çalıştırılır
  • İşlem yoksa koşul doğru olduğunda $0 yazdırılır
  • Blok içinde birden fazla ifade noktalı virgül ; ile ayrılabilir
  • Birden fazla bloğu art arda yazarak, çoğu tek satırlık komutta açık bir if kullanmadan koşula göre işlem tanımlayabilirsiniz
    • awk '$NF<0' table.txt, yalnızca son alanı negatif olan satırları yazdırır
  • BEGIN{} girdi okunmadan önce çalıştırılır
  • END{} tüm girdi işleme bittikten sonra çalıştırılır
  • Operatörler ve koşul ifadeleri hakkında ayrıntılar gawk manual: Operators ve gawk manual: Truth Values and Conditions içinde yer alır

String'ler ve sayılar

  • awk, CLI üzerinde kısa çözümler üretmeyi kolaylaştırmak için değer türünü bağlama göre yorumlar
  • String sabitleri çift tırnak içinde yazılır
  • Sayılar tamsayı, kayan noktalı ve bilimsel gösterim biçiminde kullanılabilir
  • BEGIN{} harici girdi olmadan awk programı çalıştırılırken de kullanılabilir
  • Değişkenlerde sayılar ve string'ler saklanabilir
    • Örnek: a=5; b=2.5; print a+b
    • String'ler yan yana yazıldığında birleştirilir
  • Başlatılmamış değişkenler, string bağlamında boş string; sayısal bağlamda ise 0 gibi davranır
  • Bir string sayısal ifadede kullanılırsa sayıya zorla dönüştürülür
    • String geçerli bir sayıyla başlamıyorsa 0 olarak ele alınır
    • Baştaki boşluklar yok sayılır
  • Bir sayıya string eklenirse sayı string'e dönüştürülür
  • Ayrıntılar için gawk manual: Constant Expressions ve gawk manual: How awk Converts Between Strings and Numbers bölümlerine bakabilirsiniz

Diziler

  • awk dizileri ilişkisel dizilerdir ve anahtar-değer çiftleriyle çalışır
  • Anahtarlar sayı veya string olabilir, ancak sayısal anahtarlar dahili olarak string'e dönüştürülür
  • Çok boyutlu diziler de kullanılabilir
  • Örnekte student["id"], student["name"] gibi string anahtarlarla değer saklama ve erişim gösterilir
  • Bir anahtarın varlığı "id" in student biçiminde denetlenir
  • Ayrıntılar gawk manual: Arrays bölümünde yer alır

Alıştırma ve sonraki adımlar

  • Bu bölüm, awk sözdiziminin temel kısaltmalarını, filtrelemeyi, yerine koymayı, alan işlemeyi, tür dönüşümünü ve dizileri kısaca tanıtır
  • Sonraki bölüm düzenli ifadeleri ele alır ve burada tanıtılan özellikler örneklerde kullanılmaya devam eder
  • Alan numaralarını değiştirerek ya da negatif ve kayan noktalı alan numaraları gibi farklı girdiler deneyerek sözdizimine alışabilirsiniz
  • Etkileşimli alıştırma için TUI uygulaması AwkExercises deposundan kurulabilir; kullanım bilgileri app_guide.md içinde yer alır
  • Tüm alıştırma soruları Exercises.md dosyasında toplanmıştır; çözümler ise Exercise_solutions.md dosyasında bulunur

1 yorum

 
GN⁺ 2023-08-29
Hacker News yorumları
  • awk’yi seviyorum ve epey sık kullanıyorum; başlıca kullanım alanlarımdan biri onu durum tutan sed gibi kullanmak
    Örneğin, bir satırı yalnızca belirli bir önceki satırdan sonra geldiğinde eşleştirmek gibi; geçici linter’lar yazarken işe yarıyor
    Yakın zamanda, çok büyük tablolarda sorun çıkarabilecek CREATE INDEX ifadelerinin CONCURRENTLY olmadan yer aldığı migration dosyalarını bulan bir kontrol yazdım; SQL ifadeleri birden çok satıra yayılabildiği için basit eşleştirme zordu
    awk, birden çok satır boyunca “create ifadesinin içindeyim”, “indeks oluşturuyorum” gibi durum takibi yapabildiğinden, kabaca bir araya getirdiğim script yaklaşık 1 yıldır sorunsuz çalışıyor

    • Bir gün awk öğrenmem gerekecek ama bu arada sed’in daha derin durum tabanlı özelliklerini öğrendim
      Önceki satır belirli bir desense yalnızca mevcut satırı yazdırmak için sed -ne 'x' -e '/PREV/ {x; /CURR/ p; x}' gibi yapılabiliyor
      Örnek: echo -e "PREV\nCURR\nCURR\nCURR\nPREV\nRED" | sed -ne 'x' -e '/PREV/ {x; /CURR/ p; x}' yalnızca CURR çıktısını verir
      Bu, sed’in hold buffer’ını kullanan bir yöntem; -n ile varsayılan çıktı engellenir, sonra p ile yalnızca gereken satırlar yazdırılır
      x mevcut satır ile hold buffer’ı yer değiştirir; /PREV/ { ... } bloğunda tekrar yer değiştirildikten sonra mevcut satır yalnızca CURR içeriyorsa yazdırılır
      Sondaki x, eşleşmelerin çakıştığı durumlar için tekrar geri döndürme amaçlıdır
      Elbette awk script’inin çok daha basit ve doğrudan olma ihtimali yüksek, ama sed ile de böyle yapılabiliyor
      Bunu öğrenmeye harcadığım zaman belki awk’ye ayrılsa daha iyi olurdu; ama https://www.grymoire.com/Unix/Sed.html eğitimi o kadar iyi ki sed hakkında bildiğim neredeyse her şeyi oradan öğrendim
    • SQL’in durumunu awk ile nasıl takip ettiğine dair bir örnek paylaşabilirsen iyi olur
  • Bu başlığı okuyanların 2 hafta önceki “Ask HN: Share a shell script you like” konusuyla da ilgilenebileceğini düşünüyorum
    78 yorumla beklediğim kadar çok ilgi görmedi ama bakmaya değer: https://news.ycombinator.com/item?id=37112991

  • Lisp vb. ile birlikte Awk’ye de küçük bir ilgimi sürdürüyorum ve 2022’de cppawk’yi yaptım: https://www.kylheku.com/cgit/cppawk/about/
    cppawk, Awk’ye ön işleme özellikleri ekliyor
    Birden çok maddeyi destekleyen döngü makroları var; maddeler birleştirilerek paralel iterasyon veya Kartezyen çarpım iterasyonu oluşturulabiliyor, kullanıcı tarafından genişletmek de mümkün
    5 basit makro yazarak yeni bir madde tanımlanabiliyor
    Awk kullanıyorsanız faydalı olabilir; birden fazla man page ile belgelenmiş durumda ve gawk ile mawk üzerinde çalışan birim testleri de var

  • Eski sistem yöneticisi reflekslerim ortaya çıkıyor olabilir ama aynı işi doğrudan Perl ile yazmaya kıyasla awk’nin avantajının ne olduğunu pek anlamıyorum
    Junior sistem yöneticilerinin yazdığı berbat shell script’leri çok gördüm ve her seferinde “metin işleme kısmı Perl olsaydı çok daha temiz olurdu” diye düşündüm

    • Perl’in her zaman kullanıldığı bir ortamdaysanız bu oldukça makul bir görüş
      Benim için awk, aylarca kenara bıraksam bile 10 dakikada tekrar ritmini yakalayabildiğim az sayıdaki dilden biri
      Sezgisel bir tarafı var ve yaygın komut satırı araçlarıyla da doğal biçimde iyi uyum sağlıyor
    • Script yazmak için Awk ile Perl’i karşılaştırırsam Perl veya Python’ı tercih ederim
      Ancak bu yazı geçici amaçlı kısa tek satırlık komutlar hakkında ve böyle durumlarda sed/awk Perl’den daha iyi
      Zaten Perl biliyorsanız, ek araç öğrenmeye gerek kalmadan Perl kullanmaya devam edebilirsiniz
    • Awk’nin gücü, ücretsiz gelen okuma döngüsü, alan ayırma ve desen/koşul eşleştirme modelinde
      Dilin kendisi “idare eder” düzeyde ama yeterince kullanılabilir
      Perl ile elbette bunların hepsi yapılabilir, fakat awk’nin bedava sunduğu boilerplate’i sizin yazmanız gerekir
      Perl dilinin avantajları benim için awk’den vazgeçecek kadar büyük değil; awk’yi “script yazmaktan” çok veri işleme ve tek seferlik dosya dönüştürme için kullandığımdan Perl’in derinliğini aramıyorum
      Daha derin özelliklere ihtiyaç duyarsam başka bir yere giderim
    • Teknik olarak belirgin bir avantajı yok; Perl’in özellikleri bilerek awk’nin üst kümesine yakın tasarlanmış durumda
      Günümüz kuşağı Perl öğrenmediği için akış işleme fikrini awk ile yeniden keşfediyor gibi görünüyor
      awk, 1970’lerin sonu için harika bir fikirdi ve taklit edilmeye değer gerçek bir yenilikti
      Sonra Perl bunu taklit edip aştı ama unutuldu; bu yüzden awk’nin yeniden keşfediliyor olması biraz utandırıcı
    • Alay etmiyorum; Perl’in script yazmak için neden Python’dan daha iyi olduğunu merak ediyorum
  • gawk hakkında daha az bilinen noktalardan biri, genellikle yararlı eklenti özellikleriyle birlikte gelmesidir
    readdir(), ord(), chr(), gettimeofday(), sleep() gibi işlevlere erişebilirsiniz
    https://www.gnu.org/software/gawk/manual/html_node/Extension-Samples.html

  • awk tek satırlık komutları gerçekten çok güçlü
    Zor soru, daha karmaşık awk programlamasına yatırım yapmaya değip değmeyeceği
    İşleme işi karmaşık mantık gerektiriyorsa awk bunu sunuyor, ama erken dönem bilgisayar kullanımındaki kısa ve anlaşılması güç tarzda sunuyor
    Öte yandan modern bir alternatif seçerseniz onun da yükü var; özellikle pandas gibi sezgisel olmayabilir ve performans sorunları bile çıkabilir

    • Benim için büyük sorun kütüphaneler
      Kişisel ortak fonksiyon dosyalarının bile iyi desteklendiği hissini vermiyor; üçüncü taraf kütüphaneleri içe aktarmanın da düzgün bir yolu yok gibi görünüyor
      Yardımcı fonksiyonlara ihtiyaç duyup kodu birden fazla satıra bölmeye başlayınca genelde Python’a geçiyorum
      Sonra program 2-3 kat büyüyor ve iç çekiyorum
      Ruby, awk’nin yerine harika bir alternatif; ama iş arkadaşlarınız Ruby bilmiyorsa bakım beklemek zor
    • ChatGPT’den önce anlaşılması güç awk/sed tek satırlık komutlarını sevmezdim
      Şimdilerde böyle okunması zor komutları yapay zekaya yapıştırınca adım adım oldukça iyi açıklıyor, o yüzden sorun olmaktan çıktı
      Yine de birim test edilebilirliği yüzünden birkaç satır Python’ı tercih ederim; ama hızlı veri dönüştürme işlerinde baştan birim teste gerek olmayan durumlar da oluyor
  • CLI text processing with GNU awk” e-kitabının yeni sürümü yayımlandı
    GNU awk komutunu başlangıçtan ileri seviyeye kadar yüzlerce örnek ve alıştırmayla adım adım öğrenebilir; alan işleme, filtreleme, birden çok dosya işleme, birden çok kayda dayanan çözümler, dosyalar arasında kayıt/alan karşılaştırma, giriş sırasını koruyarak yinelenenleri bulma, regex gibi konuları derinlemesine ele alabilirsiniz
    PDF/EPUB: https://learnbyexample.gumroad.com/l/gnu_awk (31 Ağustos 2023’e kadar ücretsiz)
    Web sürümü: https://learnbyexample.github.io/learn_gnuawk/
    Markdown kaynağı ve örnek dosyalar: https://github.com/learnbyexample/learn_gnuawk
    Alıştırma için etkileşimli TUI uygulaması: https://github.com/learnbyexample/TUI-apps/blob/main/AwkExercises
    Paket olarak grep, sed, awk, perl, ruby tek satırlık komut demeti Magical one-liners $5: https://learnbyexample.gumroad.com/l/oneliners/new_awk_release, 13 kitabın tamamını içeren e-kitap paketi $12: https://learnbyexample.gumroad.com/l/all-books/new_awk_release
    Yazım hataları, kod hataları, iyi oturan ya da oturmayan bölümler dahil her türlü geri bildirim çok yardımcı olur
    Önceki tartışmalar olarak https://news.ycombinator.com/item?id=15549318 ve https://news.ycombinator.com/item?id=22758217 var

    • Magical one-liners gibi kaynaklara gerçekte kaç kişinin para ödediğini ve “gördükten sonra ödeme seç” modelini hiç denemiş olup olmadığınızı merak ediyorum
      $5 ya da $15 ödeyecek kadar faydalı olabilir, ama kişisel tek satırlık komut dosyamda zaten sakladığım şeylerden farklı olmayabilir; bunu kontrol etmek için para ödemekte tereddüt ediyorum
    • Üzerine çok emek verildiği hoş bir şekilde belli oluyor; özellikle TUI uygulaması hoşuma gitti
      Web sürümünün 31 Ağustos’tan sonra da ücretsiz kalıp kalmayacağını merak ediyorum
  • Eskiden AWK ile kalp çizme golf’ü denemiştim: https://gist.github.com/auselen/906a53b47a7d616b080dbef85eb8f776

  • awk kullanımımın %99,9’u ardışık boşlukları atarak satırı bölmek için
    Örnek: echo "key: value" | awk '{print $1}'
    Daha basit bir alternatif olsa iyi olurdu

    • https://github.com/c-blake/bu/blob/main/doc/cols.md değerlendirilebilir
      Nim ile yazılmış ama bu büyük bir engel olmayabilir; bu/ içindeki diğer araçlar da ilginizi çekebilir
    • cut ile de mümkün: echo "key: value" | cut -wf 2
      Ancak gerçekten daha basit olup olmadığı tartışmaya açık
      Kontrol ettim, GNU cut’ta -w yok; BSD’ye özgüymüş
      Sonuçta awk kullanmak daha iyi olacak gibi
    • https://github.com/sstadick/hck ve https://github.com/theryangeary/choose de bakmaya değer
      İkisi de cut/awk alternatifi ve regex tabanlı ayırmayı da destekliyor; ama baştaki/sondaki boşlukları kaldırma, hatırladığım kadarıyla yok
      Kendi yaptığım https://github.com/learnbyexample/regexp-cut ise awk kullanarak regex tabanlı ayırma, negatif indeksler vb. sunan cut benzeri bir araç; awk’nin varsayılan davranışı sayesinde baştaki/sondaki boşlukları da işliyor
    • Muhtemelen echo "key: value" | awk '{print $2}' demek istediniz
  • Eskiden bash’ten port ettiğim diff2html betiğini awk ile yazmıştım; doğal olarak çok daha hızlıydı
    awk tarafı bash betiğinden çok daha okunaklıydı ve dili bir gecede öğrenip, debug edip, hataları anlayarak düzeltebilmiştim
    Bunun deyimsel awk tarzı olup olmadığını bilmiyorum ama gerçekten iyi bir dil olduğunu hissettim
    https://github.com/berry-thawson/diff2html/blob/master/diff2html.sh