sort, uniq, cut, dan tr

Perkakas agregasi sort, uniq, cut, dan tr untuk mengurutkan, menghitung, memotong, dan menerjemahkan teks.

Daftar isi

Empat perkakas kecil menutup modul ini karena hampir selalu muncul di dalam pipeline, yaitu sort untuk mengurutkan baris, uniq untuk menghitung kemunculan, cut untuk memotong field, dan tr untuk menerjemahkan karakter. Masing-masing hanya melakukan satu tugas, sedangkan penggabungannya menjadi pipeline menyelesaikan pekerjaan agregasi yang lebih besar. Topik ini membahas cara kerja keempatnya, kemudian ditutup dengan satu baris pipeline yang menghitung frekuensi kata dari sebuah berkas.

Mengurutkan baris dengan sort#

Dua berkas contoh dipakai sepanjang topik ini, yaitu daftar nilai ujian dan daftar presensi yang memuat nama berulang. Berkas presensi sengaja dibuat tidak terurut dan berulang agar perilaku uniq terlihat jelas. Kedua berkas dibuat dengan perintah berikut.

bash
# membuat berkas nilai dan berkas presensi
printf 'Ali 86\nBudi 78\nCitra 92\nDewi 81\nEka 88\n' > nilai.txt
printf 'Ali\nAli\nBudi\nAli\nCitra\nCitra\nBudi\n' > presensi.txt
cat presensi.txt
text Keluaran
Ali
Ali
Budi
Ali
Citra
Citra
Budi

Tanpa opsi apa pun, sort mengurutkan baris menurut urutan byte karakter. Opsi -n memperlakukan kunci pengurutan sebagai angka, opsi -r membalik urutannya, dan opsi -k menetapkan field yang menjadi kunci pengurutan. Urutan huruf pada sort juga bergantung pada locale, dan urutan byte memberikan hasil yang paling dapat diprediksi untuk data ASCII.

bash
# mengurutkan baris secara leksikografis
sort presensi.txt
text Keluaran
Ali
Ali
Ali
Budi
Budi
Citra
Citra
bash
# mengurutkan menurut field kedua sebagai angka
sort -k2 -n nilai.txt
# urutan menurun memunculkan nilai tertinggi lebih dulu
sort -k2 -nr nilai.txt | head -3
text Keluaran
Budi 78
Dewi 81
Ali 86
Eka 88
Citra 92
Citra 92
Eka 88
Ali 86

Opsi -k2 menjadikan field kedua sebagai kunci, sedangkan -n memastikan 92 dibaca lebih besar daripada 81. Tanpa -n, urutan teks menempatkan 100 sebelum 86 karena karakter 1 lebih awal daripada 8. Kesalahan semacam itu paling sering terjadi saat mengurutkan field angka.

Menghitung kemunculan dengan uniq#

uniq menyatukan baris bersebelahan yang identik menjadi satu baris. Kecocokannya hanya mengenali kemunculan yang berdampingan, sehingga uniq yang dijalankan langsung pada presensi.txt tidak menyatukan seluruh Ali yang tersebar. Kebiasaan yang benar adalah mengurutkan dengan sort terlebih dahulu agar seluruh baris identik bersebelahan, lalu menjalankan uniq.

bash
# uniq hanya menyatukan kemunculan yang bersebelahan
uniq presensi.txt
# pengurutan lebih dulu menyatukan seluruh kemunculan identik
sort presensi.txt | uniq
text Keluaran
Ali
Budi
Ali
Citra
Budi
Ali
Budi
Citra

Flag -c menambahkan hitungan di depan setiap baris. Hitungan dicetak rata kanan dalam bidang tersendiri, sehingga angkanya mudah dibaca meskipun lebarnya berbeda. Hasil hitungan itu biasanya diurutkan kembali untuk mencari baris yang paling sering muncul.

bash
# flag -c menambahkan hitungan di depan setiap baris
sort presensi.txt | uniq -c
# hasil hitungan diurutkan menurun untuk mencari yang terbanyak
sort presensi.txt | uniq -c | sort -rn
text Keluaran
      3 Ali
      2 Budi
      2 Citra
      3 Ali
      2 Citra
      2 Budi

Pipeline sort | uniq -c | sort -rn adalah bentuk baku untuk penghitungan kemunculan, dan bentuk ini kembali dipakai pada contoh terakhir topik ini. Keluarannya menunjukkan Ali muncul tiga kali, sedangkan Budi dan Citra masing-masing dua kali. Urutan di antara baris berhitungan sama ditentukan perbandingan lanjutan sort terhadap sisa barisnya, sehingga Citra tampil sebelum Budi pada keluaran terakhir.

Memotong field dengan cut#

cut menampilkan sebagian field dari setiap baris. Opsi -d menetapkan pembatasnya dan opsi -f menyatakan field mana yang dipilih, misalnya -f1 untuk field pertama, -f1-3 untuk rentang, dan -f1,3 untuk pilihan tak berurutan. Pembatas bawaan cut adalah karakter tab, sehingga -d wajib dituliskan bila datanya dipisahkan spasi.

bash
# mengambil field pertama berupa nama
cut -d' ' -f1 nilai.txt
# mengambil field kedua berupa nilai
cut -d' ' -f2 nilai.txt
text Keluaran
Ali
Budi
Citra
Dewi
Eka
86
78
92
81
88

Berkas nilai.txt dipisahkan satu spasi per baris, sehingga hasilnya bersih. Pada data yang memuat spasi beruntun, cut memperlakukan setiap spasi sebagai satu pembatas dan menghasilkan field kosong di antaranya. Perilaku ini berbeda dari pemecahan field pada awk. Karena itu, data dengan spasi tak beraturan lebih aman diproses dengan awk atau dibersihkan lebih dahulu dengan tr.

Menerjemahkan karakter dengan tr#

tr bekerja pada tingkat karakter, bukan field. Perintah ini menerima dua himpunan karakter, mengganti setiap karakter dari himpunan pertama dengan karakter sepadan pada himpunan kedua, dan selalu membaca masukan dari stdin. Opsi -d menghapus karakter tertentu, sedangkan opsi -s memampatkan kemunculan beruntun menjadi satu.

bash
# mengubah seluruh huruf kecil menjadi huruf besar
printf 'tugas harian\n' | tr 'a-z' 'A-Z'
# memampatkan spasi beruntun menjadi satu spasi
printf 'kolom   satu   dua\n' | tr -s ' '
text Keluaran
TUGAS HARIAN
kolom satu dua

Rentang a-z dan A-Z menyatakan himpunan huruf pada locale C. Karena tr hanya membaca stdin, masukan dari berkas disalurkan dengan redirection < atau melalui pipe. Perintah ini tidak menyimpan berkas dan tidak mengenal argumen berkas. Perbedaan desain inilah yang mendasari kesalahan yang dibahas di bagian akhir.

Pipeline frekuensi kata#

Penggabungan keempat perkakas ini menghasilkan salah satu one-liner yang paling khas di command line, yaitu penghitungan frekuensi kata. Contoh datanya adalah catatan singkat dua baris. Berkas dibuat lebih dahulu, kemudian satu baris pipeline menghitung tiga kata yang paling sering muncul di dalamnya.

bash
# membuat berkas catatan singkat
printf 'Kucing duduk di atas meja. Meja dekat jendela.\nKucing melihat burung di luar jendela.\n' > catatan.txt
# menghitung frekuensi kata dengan satu baris pipeline
tr -cs 'A-Za-z' '\n' < catatan.txt | tr 'A-Z' 'a-z' | sort | uniq -c | sort -rn | head -3
text Keluaran
      2 meja
      2 kucing
      2 jendela

Setiap tahap pipeline di atas menjalankan satu tugas dalam urutan sebagai berikut.

  1. tr -cs 'A-Za-z' '\n' mengganti setiap karakter selain huruf dengan baris baru dan memampatkannya, sehingga setiap kata berada di baris sendiri.
  2. tr 'A-Z' 'a-z' menyamakan seluruh huruf menjadi huruf kecil agar Kucing dan kucing dihitung sebagai kata yang sama.
  3. sort mengurutkan seluruh kata sehingga kata identik bersebelahan.
  4. uniq -c menghitung kemunculan setiap kata.
  5. sort -rn mengurutkan hasil hitungan dari yang terbesar, dan head -3 membatasi tampilan tiga baris teratas.

Empat kata sama-sama muncul dua kali, yaitu di, jendela, kucing, dan meja, sedangkan head -3 hanya menampilkan tiga di antaranya. Urutan di antara baris berhitungan sama ditentukan perbandingan lanjutan sort terhadap sisa barisnya. Pipeline sepanjang satu baris ini menggantikan program yang pada bahasa pemrograman lengkap membutuhkan kamus dan perulangan.

Kesalahan umum#

uniq dijalankan tanpa sort. Baris identik yang tidak bersebelahan tidak disatukan, sehingga hasilnya menyisakan kemunculan ganda yang tampak sudah dihitung. Pengurutan dengan sort sebelum uniq adalah syarat kerjanya, bukan pilihan gaya.

cut ditulis tanpa -d. Pembatas bawaan cut adalah tab, sehingga cut -f1 pada data berpembatas spasi mengembalikan baris utuh tanpa memotong apa pun. Opsi -d' ' perlu dituliskan secara eksplisit untuk data yang dipisahkan spasi.

tr diberi nama berkas. Perintah tr tidak menerima argumen berkas karena selalu membaca masukan dari stdin.

bash
# tr tidak menerima nama berkas karena selalu membaca stdin
tr 'a-z' 'A-Z' nilai.txt
text Keluaran
tr: extra operand ‘nilai.txt’
Try 'tr --help' for more information.

Pesan error di atas menyatakan argumen ketiga dianggap operand tambahan yang tidak dipahami. Perbaikannya adalah memberi masukan melalui redirection, misalnya tr 'a-z' 'A-Z' < nilai.txt, atau melalui pipe.

Ringkasan#

  • sort mengurutkan baris, dengan -k untuk kunci field, -n untuk angka, dan -r untuk urutan menurun.
  • uniq menyatukan baris bersebelahan yang identik, dan sort | uniq -c | sort -rn adalah bentuk baku penghitungan kemunculan terbanyak.
  • cut memilih field menurut pembatas dengan -d dan -f, dengan tab sebagai pembatas bawaannya.
  • tr menerjemahkan atau menghapus karakter dan selalu membaca masukan dari stdin.
  • Pipeline tr | sort | uniq -c | sort -rn menghitung frekuensi kata dalam satu baris.

Referensi#