14 Ocak 2015 Çarşamba

awk komutu

Giriş
Not : awk satırlar üzerinde çalışır. grep'in tersine satırı daha küçük parçalara ayırabilme yeteneği vardır. Son yıllarda Perl de awk gibi tek satırlık işlemlerde çokça kullanılmaya başladı.

awk kelimesi geliştiricileri olan Aho, Weinberger, Kernighan'ın baş harflerinden gelmektedir. Awk interpreted bir dildir. Tek tırnak içine verilen dil awk uygulaması tarafından yorumlanır ve çalıştırılır. Şekli aşağıdaki gibidir.
awk '...' file
Tek tırnak içine ( yani '..' içine ) süslü parantez kullanarak kod yazılır. Kodlardan End {..} şeklinde olanlar awk biterken çalıştırılır. ASCII karakteri kullanmak istersek çift tırnak içinde yazarız.

Awk Seçenekleri
-F ile ayraç tanımlama
Örnek'te ayraç olarak süslü parantezin kullanılması gösterilmiş. Süslü parantez \ ile escape ediliyor.


awk -F\} '{a[$2]++} END {for (i in a) printf "%-10s %s\n",i,a[i]}' file
-v ile değişken tanımlama
-v var=value şeklinde çalışır. awk programlama dili içinde dışarıdan ilklendirilen bir değişken kullanmak isteryebiliriz. Örnek'te user değişkeni awk içinde kullanılmak isteniyor.
awk -F: -v user=$myuser '$1==user { print $6 ;}' /etc/passwd
Örnekte verilen sayı kadar sütüna sahip satırlar print ediliyor.
awkcommand() { awk -F '|' -v n=$nbfields 'NF==n' file; }

Awk Programlama Yapıları
Her dili öğrenirken olduğu gibi önce programlama yapılarına bakma gerekir. kıyas opeatörleri, döngüler, koşullar vs. 
Koşullar
if/ else if koşulu örneği aynı C'deki gibidir. Awk strongly-typed bir dil değildir. Her değişken string olarak kabul edilir ancak string bir sayı ise aritmetik işlemler de yapılabilir.
awk '{if($3 != 0) {print $0} else if($3==0) print $0, "-" }' file
For Döngüsü
Sayı Üzerinde Dönmek
For döngüsü klasik C dilindeki döngüye benziyor. Döngü için bir değişken tanımlanır. Bu değişkene başlangıç değeri atanır. Bitiş koşulu tanımlanır. Değişken artırılır veya azaltılır. Döngü içindeki koşul {..} içine yazılır.

Örnek'te alanlar tersten yazılıyor. 
awk -F'.' '{for (i=NF;i>1;i--){printf $i"."};print $1}'
Veri Yapısı Üzerinde Dönmek
Bu yapı da C#'taki foreach yapısına benziyor. Bir değişken ve veriyapısı kullanılır.

Awk Veri Yapıları
 associative array
Associate array değişken[key] = value şeklinde kullanılır.

Key ilk tanımlanırken value 0'dır
Örnek'te ls komutunun çıktısının 6. sütunu (tarih alanı) anahtar olarak kullanılıyor ve 5. sütün (dosya büyüklüğü) ile toplanıyor. Böylece SQL'deki "group by" gibi gün bazında dosya büyüklükleri bulunuyor. awk sona ererken tüm sözlüğü key alanına göre ekrana yazıyor.

ls -l --time-style=long-iso *log |
    awk '{sum[$6]+= $5;} END{for (s in sum){print s , sum[s];}}'


Bir başka örnek'te birden fazla olan aynı satırla siliniyor. a[$0] ile key = 0 şeklinde yeni bir çift yaratılır veya mevcut value değerine erişilir. ++ ile eski değer döner ve değer bir artırılır.
! ile değer sıfırsa default action olan print $0 çağırılır. 
awk '!(a[$0]++)' <f

Awk Built-In Değişkenler
Listedeki değişkenlere bazı örneker.
FNR - Number of Records
Dosyanın içindeki kaçıncı kayıt olduğunu belirtir. Her dosyadan 2. satırı alan örnek şöyle
awk 'FNR==2{print $0 > "output.dat"}' file{1..80}.dat
NR - Total Number of Records
Birden fazla dosya varsa, toplamda kaçıncı kayıt olduğunu belirtir. FNR ve NR farkını burada görebilirsiniz. Tek dosya varsa FNR ve NR aynı işi görürler. Esinlenerek oluşturduğum örnekte çift satırlar çıktıya dahil ediliyor.
awk 'NR%2{print "$0}' file
NF - Number of Fields
Satırda kaç tane alan olduğunu belirtir. Son sütuna erişmek için örnek:
awk '{print $NF}' file
RS - Record Separator
Awk dosyayı okurken record'un nerede bittiğini anlamak için RS değerine bakar. Normalde RS için awk newline karakterini kullanır. Böylecek awk satırlar ile çalışmış olur. 
Örnek'te free kelimesinden önce gelen kelimeyi bulma gösteriliyor. Record separator virgül olarak atanıyor. Böylece her alan yeni bir satır gibi işleniyor. Eğer satır (yani alanda) free kelimesi yoksa a değişkeninde saklanıyor. free kelimesi varsa a karakteri yazılıyor.
awk -v RS="[, ]" '/free/{print a}{a=$0}'
ORS - Output Record Separator
Bir record print edilirken sonuna ORS karakteri konulur. Örnek'te ORS çift sayılarda boşluk tek sayılarda \n olacak şekilde değiştiriliyor. Böylece arka arkaya gelen iki satır yanyana olacak hale getiriliyor.
awk '{ORS=NR%2?" ":"\n";print}' file

Awk Programlama Dilinde Print
print ve printf en çok kullanılan metodlar oldukları için özel yer ayırmak istedim. printf C dilindeki eşleniğine çok benziyor.

%s kullanımı
Örnek:
awk -F: -v user=$myuser '$1==user { printf "%s/.ssh\n",$6;}' /etc/passwd

Awk Programlama Dili
regex match
Regex match için aşağıdaki örüntü kullanılır. // karakterler arasına aranan kelime yazılır. Eğer satırda aranan kelime varsa pattern'den sonra gelen ilk süslü parantez işletilir. Bu kod grep ile aynı işlevi görür.
awk '/pattern/{ print $0 }' file
Bir başka örnekte sadece 2. alanda regex match yapılıyor.
awk -F, '$2 ~ /jpn|por/ {print}' file1.csv > file2.csv
Bir başka örnekte bloklar şeklinde regex match yapılıyor. History içeren ilk satır ile Date kelimesini içeren ilk satır arasında kalan block siliniyor.
awk '/History/ , /Date/{ next }1' file
normal match
Örnek'te 2. alanı agt olan satırlar yazdırılıyor.
$ awk '$2=="agt"' file
okunan sütuna değer atama
Örnekte ilk sütun boş string değeri atanarak siliniyor.
awk '{$1="";print $0}' FileName > NewFileName

next komutu
Bu komut ile bir sonraki satır okunur. İki satırı birleştirip tek satır haline getiren örnek. Her çift sayılı satırda elimizdeli satırı a değişkeninde saklar ve bir sonraki satırı okur. Daha sonra a ve sonraki satırı virgül ile birleştirerek yazar.
$ awk 'NR%2{a=$0;next}{print a","$0}' file
concat işlemi - birleştirme
Birleştirmek istenen string sütunun yanına yazılır. Örnekte 3. sütunun sonuna dolar işareti ekleniyor.
awk '{$3 = $3"$"; print}' infile > outfile

substr komutu - kesit alma
Örnek'te birinci sütunun ilk 6 karakteri alınıyor. 
awk -F'|' '{print substr($1,1,6),$2}' OFS='|' inputfile
awk ve sözlük (dictionary)
Örnek'te ls komutunun çıktısının 6. sütunu (tarih alanı) anahtar olarak kullanılıyor ve 5. sütün (dosya büyüklüğü) ile toplanıyor. Böylece SQL'deki "group by" gibi gün bazında dosya büyüklükleri bulunuyor. awk sona ererken tüm sözlüğü key alanına göre ekrana yazıyor.

ls -l --time-style=long-iso *log |
    awk '{sum[$6]+= $5;} END{for (s in sum){print s , sum[s];}}'


Bir başka örnek burada.

Hiç yorum yok:

Yorum Gönder