İçeriğe geç
academia.sh

Ders 18 / 24

Sıralama, Tekilleştirme ve Birleştirme

Anahtara göre sıralama, yerel ayarın sıralama düzenine etkisi, komşuluk gerektiren tekilleştirme ve sıralı akışlar üzerinde küme işlemleri.

İçindekiler

Önceki derslerde her sayım sort ile bitirildi ama komutun kendisi açıklanmadı. Sıralama, kabuk metin işlemenin en çok çağrılan ikinci aracıdır ve iki nedenle ayrı bir ders hak eder: seçenekleri sonucu tümüyle değiştirir ve yanındaki üç araç — tekilleştirme, karşılaştırma, birleştirme — girdilerinin sıralı olmasına dayanır.

Algoritmalar kursunda sıralamanın maliyeti ve kararlılık ölçütü tanımlanmıştı. Bu ders o kavramları bir komutun seçeneklerine bağlar.

Sözlük Sırası ve Sayısal Sıra

Öntanımlı karşılaştırma sözlük sırasıdır: değerler karakter karakter karşılaştırılır.

printf '10\n9\n100\n2\n' | sort
10
100
2
9
printf '10\n9\n100\n2\n' | sort -n
2
9
10
100

Sözlük sırasında 10, 9’dan önce gelir çünkü ilk karakteri 1, 9’dan küçüktür. Sayıların sıralandığı her yerde -n gerekir; unutulması, raporların en sık görülen sessiz hatasıdır.

-r sırayı tersine çevirir. -n -r birlikte, çoktan aza sıralamanın standart yazımıdır.

Anahtar Tanımı

-k seçeneği, karşılaştırmanın hangi alan üzerinden yapılacağını belirtir. Yazımı -k başlangıç,bitiş biçimindedir ve bitişin yazılması zorunludur: -k2 yazımı “ikinci alandan satır sonuna kadar” anlamına gelir, -k2,2 yalnızca ikinci alanı seçer.

awk '{ print $7, $10 }' erisim.log | sort -k2,2n | head -3
/eski-sayfa 0
/giris 0
/statik/stil.css 0

Sayısal kip anahtara da eklenebilir: -k2,2n yazımı yalnızca o anahtar için geçerlidir. Birden çok -k verilirse anahtarlar sırayla uygulanır ve ilk eşitlikte sonraki anahtara geçilir.

-t ayırıcıyı belirler. Öntanımlı ayırıcı, alan tabanlı araçtan farklıdır: boşluk kümesinden boşluk olmayana geçiş noktası ayırıcı sayılır.

printf 'c:3\na:1\nb:2\n' | sort -t: -k2,2n
a:1
b:2
c:3

Kararlılık

Sıralama öntanımlı olarak kararlı değildir: eşit anahtarlı satırların göreli sırası korunmaz. Eşitlik durumunda son çare olarak satırın tamamı karşılaştırılır.

printf 'b 1\na 1\nc 0\n' | sort -k2,2n
c 0
a 1
b 1
printf 'b 1\na 1\nc 0\n' | sort -s -k2,2n
c 0
b 1
a 1

-s seçeneği son çare karşılaştırmasını kapatır ve girdi sırasını korur. Çok anahtarlı sıralamalarda — önce şehre, sonra kararlı biçimde tarihe göre — Algoritmalar kursunda gösterilen kararlılık gereksinimi bu seçenekle karşılanır.

Yerel Ayar

Karşılaştırma düzeni, çalışma ortamının yerel ayarına bağlıdır.

printf 'a\nB\nb\nA\n' | LC_ALL=C sort
A
B
a
b
printf 'a\nB\nb\nA\n' | LC_ALL=en_US.UTF-8 sort
a
A
b
B

İlk düzen bayt değerine göre, ikincisi harf temeline göre sıralar. İkisi de doğrudur; sorun, hangisinin uygulanacağının betiği çalıştıran ortama bağlı olmasıdır.

Bu, betiklerde yeniden üretilemez sonuçların başlıca kaynağıdır. Aynı betik iki makinede farklı sıralı çıktı verir; bir çıktıyı diğeriyle karşılaştıran bir sınama, gerçek bir fark olmadığı hâlde başarısız olur.

Kural: betikte sıralama yapılıyorsa yerel ayar açıkça sabitlenir.

LC_ALL=C sort ...

LC_ALL=C bayt sırasını seçer; hızlıdır, öngörülebilirdir ve makineler arasında aynıdır. İnsan okuyucu için harf temelli sıra isteniyorsa yerel ayar yine açıkça yazılmalıdır — belirsiz bırakılmamalıdır.

Ayrıca sort -u ve uniq gibi işlemler “eşitlik” tanımını yerel ayardan aldığı için, farklı ayarlarda farklı sayıda satır üretebilir. Sabitleme bu nedenle yalnızca sıra meselesi değildir.

Tekilleştirme

uniq, komşu yinelenen satırları teke indirir. Sıralanmamış girdide beklendiği gibi çalışmaz:

printf 'a\nb\na\n' | uniq -c
printf 'a\nb\na\n' | sort | uniq -c
   1 a
   1 b
   1 a
   2 a
   1 b

İlk çağrıda hiçbir şey birleştirilmedi çünkü yinelenen a satırları komşu değildi. Bu, kursun ilk konusundan beri kullanılan sort | uniq -c deseninin gerekçesidir.

Seçenekler farklı soruları yanıtlar:

Seçenek Çıktı
-c her satırın önüne yineleme sayısı
-d yalnızca birden çok kez geçen satırlar
-u yalnızca bir kez geçen satırlar
-i büyük–küçük harf ayrımsız karşılaştırma
printf 'a\nb\nb\nc\n' | uniq -u
a
c

sort -u ile sort | uniq aynı sonucu verir ama sort -u daha ucuzdur: ayrı bir süreç yaratılmaz. uniq -c gerekiyorsa iki adım zorunludur, çünkü sort -u sayım yapmaz.

Küme İşlemleri

comm, iki sıralı dosyayı karşılaştırır ve üç sütun üretir: yalnızca birincide olanlar, yalnızca ikincide olanlar, ikisinde de olanlar. -1, -2, -3 seçenekleri ilgili sütunu bastırır.

Kütüğün ilk ve son on beş satırında istenen yolları karşılaştıralım. İki dosya da tekilleştirilmiş ve aynı yerel ayarla sıralanmış olarak hazırlanır:

export LC_ALL=C
head -15 erisim.log | cut -d' ' -f7 | sort -u > dun.txt
tail -15 erisim.log | cut -d' ' -f7 | sort -u > bugun.txt
comm -23 dun.txt bugun.txt      # yalniz birincide
/giris
comm -13 dun.txt bugun.txt      # yalniz ikincide
/eski-sayfa
comm -12 dun.txt bugun.txt      # ortak
/api/veri
/gizli
/index.html
/panel
/statik/stil.css
/urun/12
/urun/45
/yok.html

Üç çağrı sırasıyla küme farkını, ters farkı ve kesişimi verir. İki dosya da sıralı olmalıdır ve aynı yerel ayarla sıralanmış olmalıdır; aksi hâlde comm uyarı verir ya da sessizce yanlış sonuç üretir.

Bu araç, iki kütüğü karşılaştırmanın doğrudan yoludur: hangi yollar yalnızca bu dönemde istendi, hangi istemciler kayboldu, hangi hata kodları yeni ortaya çıktı.

join, iki sıralı dosyayı ortak bir anahtar alanı üzerinden birleştirir; ilişkisel veritabanlarındaki birleştirme işleminin metin karşılığıdır.

Yol başına istek sayısını ve toplam baytı iki ayrı dosyada üretip anahtarlarına göre sıralayalım:

awk '{ sayim[$7]++ }     END { for (y in sayim) print y, sayim[y] }' erisim.log | sort -k1,1 > adet.txt
awk '{ bayt[$7] += $10 } END { for (y in bayt)  print y, bayt[y]  }' erisim.log | sort -k1,1 > boyut.txt
join adet.txt boyut.txt | head -5
/api/veri 6 7236
/eski-sayfa 1 0
/giris 1 0
/gizli 2 580
/index.html 4 20480

Öntanımlı olarak her iki dosyanın birinci alanı anahtar sayılır; -1 ve -2 seçenekleri alan numarasını değiştirir, -t ayırıcıyı belirler. Girdilerin anahtar alanına göre sıralı olması zorunludur — satırın tamamına göre değil. Bu ayrım, join kullanımındaki en sık hatanın kaynağıdır.

Belirlenimci Sıralama

Sayım çıktılarında eşit sayılı satırların sırası, son çare karşılaştırmasına ve yerel ayara bağlıdır. Bu, raporun her çalıştırmada aynı çıkmasını engelleyebilir:

cut -d' ' -f7 erisim.log | sort | uniq -c | sort -rn | head -5
   6 /api/veri
   4 /yok.html
   4 /index.html
   3 /urun/45
   3 /urun/12

İkincil anahtar açıkça verildiğinde sonuç belirlenimci olur: önce sayıya göre azalan, eşitlikte ada göre artan.

cut -d' ' -f7 erisim.log \
  | LC_ALL=C sort | uniq -c | LC_ALL=C sort -k1,1nr -k2,2 | head -5
   6 /api/veri
   4 /index.html
   4 /yok.html
   3 /panel
   3 /statik/stil.css

Eşit sayılı satırlar artık alfabetik sırada. Çıktısı sınanacak ya da iki çalıştırma arasında karşılaştırılacak her betikte bu yazım kullanılmalıdır.

Betiğe Uygulama

rapor.sh iki değişiklik alır. Birincisi, tüm sıralamaların yerel ayarı sabitlenir ve ikincil anahtar verilir:

export LC_ALL=C

en_cok() {                      # en_cok ALAN DOSYA ADET
  local alan="$1" dosya="$2" adet="$3"
  cut -d' ' -f"$alan" "$dosya" | sort | uniq -c | sort -k1,1nr -k2,2 | head -"$adet"
}

export LC_ALL=C betiğin başına konur; böylece çağrılan tüm araçlar aynı düzeni kullanır. Bu, betiğin çıktısını çalıştırıldığı ortamdan bağımsız kılar.

İkincisi, iki kütüğü karşılaştıran bir seçenek eklenir:

karsilastir() {                 # karsilastir ESKI YENI
  local eski="$1" yeni="$2"
  cut -d' ' -f7 "$eski" | sort -u > "$gecici/eski"
  cut -d' ' -f7 "$yeni" | sort -u > "$gecici/yeni"
  bolum "Yalnizca yeni kutukte gorulen yollar"
  comm -13 "$gecici/eski" "$gecici/yeni"
}

Bu fonksiyon geçici dosyalara yazıyor ve onları temizlemiyor. Sağlam Betik Yazımı konusunda mktemp ve tuzaklarla bu eksik giderilecek.

Özet

  • Öntanımlı karşılaştırma sözlük sırasıdır; sayısal veride -n zorunludur.
  • -k başlangıç,bitiş anahtarı sınırlar; bitiş yazılmazsa anahtar satır sonuna uzanır.
  • Sıralama öntanımlı olarak kararlı değildir; -s son çare karşılaştırmasını kapatır.
  • Karşılaştırma düzeni yerel ayara bağlıdır; betiklerde LC_ALL=C ile sabitlenmelidir.
  • uniq yalnızca komşu yinelemeleri birleştirir; sort | uniq -c deseni bu yüzden ayrılmazdır.
  • comm ve join sıralı girdi ister; ilki küme işlemleri, ikincisi anahtar üzerinden birleştirme yapar.

Sonraki Adım

Bu konudaki araçların hepsi satır düzeyinde çalıştı. Sütun düzeyinde kesme, iki dosyayı yan yana yapıştırma ve büyük bir kütüğü parçalara bölme ayrı bir araç öbeği gerektirir. Sonraki ders bu öbeği ele alır ve metin işleme konusunu, hangi işin hangi araca ait olduğunu belirleyen bir seçim ölçütüyle kapatır.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat