- 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
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 INDEXifadelerininCONCURRENTLYolmadan 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 zorduawk, 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
Ö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ızcaCURRçıktısını verirBu, sed’in hold buffer’ını kullanan bir yöntem;
-nile varsayılan çıktı engellenir, sonrapile yalnızca gereken satırlar yazdırılırxmevcut satır ile hold buffer’ı yer değiştirir;/PREV/ { ... }bloğunda tekrar yer değiştirildikten sonra mevcut satır yalnızcaCURRiçeriyorsa yazdırılırSondaki
x, eşleşmelerin çakıştığı durumlar için tekrar geri döndürme amaçlıdırElbette 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
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
Geçen yıldan bir yazı da var: https://news.ycombinator.com/item?id=32467957 (374 puan, 294 yorum)
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
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
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
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
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ı
gawk hakkında daha az bilinen noktalardan biri, genellikle yararlı eklenti özellikleriyle birlikte gelmesidir
readdir(),ord(),chr(),gettimeofday(),sleep()gibi işlevlere erişebilirsinizhttps://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
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
Ş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 awkkomutunu 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 alabilirsinizPDF/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
$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
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
Nim ile yazılmış ama bu büyük bir engel olmayabilir;
bu/içindeki diğer araçlar da ilginizi çekebilircutile de mümkün:echo "key: value" | cut -wf 2Ancak gerçekten daha basit olup olmadığı tartışmaya açık
Kontrol ettim, GNU cut’ta
-wyok; BSD’ye özgüymüşSonuçta awk kullanmak daha iyi olacak gibi
İ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
awkkullanarak regex tabanlı ayırma, negatif indeksler vb. sunancutbenzeri bir araç; awk’nin varsayılan davranışı sayesinde baştaki/sondaki boşlukları da işliyorecho "key: value" | awk '{print $2}'demek istedinizEskiden 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