Topik ini merakit seluruh rancangan menjadi skrip utuh cadangkan-catatan.sh, lalu membuktikannya dengan demo bertahap, pengujian mode kegagalan, audit shellcheck, dan dokumentasi. Skripnya memakai strict mode, getopts, trap, fungsi log, dan perintah tar yang seluruhnya merupakan materi jalur ini, sehingga proyek penutup ini sekaligus menjadi tinjauan ulang materi jalur. Setelah membaca topik ini, skrip proyek dapat dibaca bagian per bagian, dijalankan ulang dari nol, dan diperiksa mutunya dengan alat yang sama seperti pada artikel ini.
Skrip utuh proyek#
Skrip proyek disusun mengikuti urutan kotak pada diagram rancangan, yaitu fungsi pesan terlebih dahulu, lalu penguraian opsi, validasi, penomoran, pengemasan, dan rotasi. Berkas lengkapnya ditampilkan berikut ini dan tersedia sebagai berkas cadangkan-catatan.sh di samping artikel ini, sehingga penyalinan maupun pengeditan langsung sama-sama dapat dilakukan.
#!/usr/bin/env bash
# cadangkan-catatan.sh — cadangan berkala untuk direktori catatan teks
#
# Skrip ini mengemas satu direktori catatan menjadi arsip tar.gz bernomor
# urut, menjaga jumlah cadangan agar tidak melebihi batas tertentu, dan
# mencatat setiap langkah ke log. Contoh pemakaian:
#
# ./cadangkan-catatan.sh -s catatan -d cadangan -n 3
#
# Prasyarat: bash, tar, gzip, dan find.
set -euo pipefail
penggunaan() {
printf 'Penggunaan: %s -s direktori_sumber [-d direktori_cadangan] [-n jumlah_maksimum] [-h]\n' "$0"
}
log() {
printf '%s\n' "[INFO] $*"
}
gagal() {
printf '%s\n' "[ERROR] $*" >&2
}
# ------------------------------------------------------------------ opsi
sumber=""
tujuan="cadangan"
maksimum="3"
while getopts ":s:d:n:h" opt; do
case "$opt" in
s) sumber=$OPTARG ;;
d) tujuan=$OPTARG ;;
n) maksimum=$OPTARG ;;
h)
penggunaan
exit 0
;;
\?)
gagal "opsi tidak dikenal: -$OPTARG"
penggunaan >&2
exit 2
;;
:)
gagal "opsi -$OPTARG membutuhkan nilai"
penggunaan >&2
exit 2
;;
esac
done
shift $((OPTIND - 1))
if [ "$#" -gt 0 ]; then
gagal "argumen posisional tidak dipakai: $1"
penggunaan >&2
exit 2
fi
if [ -z "$sumber" ]; then
gagal "opsi -s wajib diberikan"
penggunaan >&2
exit 2
fi
case "$maksimum" in
''|*[!0-9]*)
gagal "opsi -n harus berupa bilangan bulat positif, diterima: $maksimum"
exit 2
;;
esac
if [ "$((10#$maksimum))" -lt 1 ]; then
gagal "opsi -n minimal 1, diterima: $maksimum"
exit 2
fi
if [ ! -d "$sumber" ]; then
gagal "direktori sumber tidak ada: $sumber"
exit 1
fi
mkdir -p "$tujuan"
# direktori sementara untuk penulisan arsip, dibersihkan oleh trap EXIT
sementara=$(mktemp -d)
trap 'rm -rf "$sementara"' EXIT
# daftar arsip yang sudah ada, diurutkan menaik
mapfile -t daftar_arsip < <(find "$tujuan" -maxdepth 1 -type f -name 'cadangan-*.tar.gz' | sort)
# nomor berikutnya mengikuti nomor tertinggi yang valid sehingga urutan
# cadangan tidak bergantung pada jumlah arsip yang tersisa
nomor=1
for (( i = ${#daftar_arsip[@]} - 1; i >= 0; i-- )); do
akhiran=${daftar_arsip[i]##*/}
angka=${akhiran#cadangan-}
angka=${angka%.tar.gz}
case "$angka" in
''|*[!0-9]*) continue ;;
esac
nomor=$((10#$angka + 1))
break
done
printf -v nama_arsip 'cadangan-%03d.tar.gz' "$nomor"
jalur_arsip=$tujuan/$nama_arsip
# ------------------------------------------------------------------ pengemasan
log "sumber: $sumber"
log "tujuan: $tujuan"
tar -czf "$sementara/$nama_arsip" "$sumber"
mv "$sementara/$nama_arsip" "$jalur_arsip"
log "arsip: $jalur_arsip"
# ------------------------------------------------------------------ rotasi
# arsip yang baru dibuat ikut dihitung, sehingga jumlah cadangan sekarang
# adalah jumlah arsip lama ditambah satu
maks=$((10#$maksimum))
jumlah_baru=$(( ${#daftar_arsip[@]} + 1 ))
lebih=$(( jumlah_baru - maks ))
if [ "$lebih" -gt 0 ]; then
# elemen pertama daftar terurut adalah arsip tertua
for (( i = 0; i < lebih; i++ )); do
log "rotasi: menghapus ${daftar_arsip[i]}"
rm -- "${daftar_arsip[i]}"
done
sisa=$maks
else
sisa=$jumlah_baru
fi
log "jumlah cadangan: $sisa dari maksimum $maks"Beberapa baris layak diberi perhatian khusus karena merangkum materi beberapa topik sekaligus. Baris set -euo pipefail menyalakan strict mode, yakni aturan berhenti secepatnya yang dibahas tuntas pada topik strict mode, sehingga kegagalan perintah mana pun menghentikan skrip. Pernyataan trap 'rm -rf "$sementara"' EXIT menghapus direktori sementara hasil mktemp -d sebagaimana dibahas pada topik penanganan error, sehingga tidak ada arsip setengah jadi yang tertinggal apabila skrip berhenti mendadak. Daftar arsip lama dikumpulkan dengan find yang dipipa ke sort lalu dibaca mapfile menjadi array, dan nomor arsip berikutnya diambil dari nomor tertinggi yang valid, bukan dari jumlah arsip, agar penomoran tetap benar setelah rotasi menghapus arsip tertua.
Menjalankan skrip pertama kali#
Demo dimulai dari keadaan bersih dengan direktori catatan tiga berkas yang sama seperti pada topik pemilihan proyek. Persiapan ini tidak mencetak apa pun, sedangkan pemanggilan skrip sesudahnya mencetak empat baris log sebagaimana dirancang pada topik rancangan proyek.
# menyiapkan direktori catatan contoh dan membersihkan sisa demo sebelumnya
rm -rf catatan cadangan
mkdir -p catatan
printf 'daftar belanja minggu ini\n' > catatan/belanja.txt
printf 'ide artikel: otomasi cadangan\n' > catatan/ide.txt
printf 'catatan rapat 6 november 2026\n' > catatan/rapat.txt# menjalankan skrip dengan opsi sumber, tujuan, dan jumlah maksimum
bash cadangkan-catatan.sh -s catatan -d cadangan -n 3[INFO] sumber: catatan
[INFO] tujuan: cadangan
[INFO] arsip: cadangan/cadangan-001.tar.gz
[INFO] jumlah cadangan: 1 dari maksimum 3Tiga perintah manual pada topik pemilihan proyek kini menjadi satu pemanggilan, dan setiap langkahnya tercatat. Arsip yang dihasilkan diverifikasi isinya dengan tar -tzf sebagaimana kebiasaan pada topik arsip, sedangkan opsi -d dan -n sengaja ditulis eksplisit pada demo meskipun nilai bawaannya sama, agar contoh tidak bergantung pada nilai bawaan.
# menampilkan isi direktori cadangan
ls -1 cadangancadangan-001.tar.gz# memeriksa isi arsip hasil skrip tanpa mengekstraknya
tar -tzf cadangan/cadangan-001.tar.gz | sortcatatan/
catatan/belanja.txt
catatan/ide.txt
catatan/rapat.txtDaftar isi arsip memperlihatkan ketiga berkas catatan beserta entri direktorinya, dengan struktur dan izin yang tetap dipertahankan sebagaimana perilaku tar pada topik arsip. Arsip ini dapat dibuka kembali dengan tar -xzf ke direktori lain apabila pemulihan benar-benar diperlukan, sehingga rantai cadangan dari pengemasan sampai pemulihan lengkap. Empat baris lognya pula terbaca sebagai ringkasan satu kali pemanggilan, yaitu dua baris pengesahan masukan, satu baris hasil pengemasan, dan satu baris hitungan akhir.
Menguji rotasi cadangan#
Fitur rotasi terlihat hanya setelah jumlah cadangan melewati batas, sehingga skrip dijalankan dua kali lagi hingga kuota tiga terpenuhi. Daftar arsip kemudian ditampilkan dengan ls -1, dan urutannya sesuai nomor karena penamaan bernomor pada rancangan.
# menjalankan skrip dua kali lagi sehingga jumlah cadangan mencapai batas
bash cadangkan-catatan.sh -s catatan -d cadangan -n 3
bash cadangkan-catatan.sh -s catatan -d cadangan -n 3
ls -1 cadangan[INFO] sumber: catatan
[INFO] tujuan: cadangan
[INFO] arsip: cadangan/cadangan-002.tar.gz
[INFO] jumlah cadangan: 2 dari maksimum 3
[INFO] sumber: catatan
[INFO] tujuan: cadangan
[INFO] arsip: cadangan/cadangan-003.tar.gz
[INFO] jumlah cadangan: 3 dari maksimum 3
cadangan-001.tar.gz
cadangan-002.tar.gz
cadangan-003.tar.gzPemanggilan keempat membuat jumlah cadangan menjadi empat, yaitu satu lebih banyak dari batas, sehingga rotasi menghapus arsip tertua dan jumlahnya kembali tiga. Perhatikan bahwa nomor arsip baru melanjutkan deret menjadi cadangan-004.tar.gz meskipun cadangan-001.tar.gz sudah dihapus, karena nomor diambil dari nomor tertinggi yang ada dan bukan dari hitungan arsip.
# menjalankan skrip keempat kali sehingga rotasi menghapus arsip tertua
bash cadangkan-catatan.sh -s catatan -d cadangan -n 3
ls -1 cadangan[INFO] sumber: catatan
[INFO] tujuan: cadangan
[INFO] arsip: cadangan/cadangan-004.tar.gz
[INFO] rotasi: menghapus cadangan/cadangan-001.tar.gz
[INFO] jumlah cadangan: 3 dari maksimum 3
cadangan-002.tar.gz
cadangan-003.tar.gz
cadangan-004.tar.gzAngka rotasinya dapat diperiksa ulang dengan hitungan sederhana, yaitu jumlah arsip lama ditambah satu dikurangi kuota, sehingga kuota tiga dengan tiga arsip lama menghasilkan tepat satu penghapusan. Apabila skrip dipanggil dengan -n 2, kelebihan pada setiap keadaan tetap satu berkas per pemanggilan, sehingga arsip tersisa selalu sebanyak kuota. Baris rotasi: menghapus pada log menjadi jejak satu-satunya untuk kejadian yang tidak dapat dibatalkan, dan itulah alasan setiap penghapusan dicatat.
Menguji mode kegagalan#
Mode kegagalan pada rancangan diuji satu per satu agar respons skripnya terbukti, bukan sekadar tertulis. Setiap pemanggilan gagal diikuti printf yang mencetak kode keluarnya, karena kode keluar adalah kontrak antara skrip dan pemanggilnya. Pemanggilan pertama meninggalkan opsi -s, dan skrip merespons dengan pesan error diikuti pesan penggunaan.
# memanggil skrip tanpa opsi wajib -s
bash cadangkan-catatan.sh -d cadangan
printf 'kode keluar: %s\n' "$?"[ERROR] opsi -s wajib diberikan
Penggunaan: cadangkan-catatan.sh -s direktori_sumber [-d direktori_cadangan] [-n jumlah_maksimum] [-h]
kode keluar: 2Pemanggilan kedua memberi nilai -n yang bukan angka, dan pola validasi dari purwarupa topik rancangan menolaknya sebelum ada berkas disentuh.
# memberi opsi -n yang bukan bilangan bulat positif
bash cadangkan-catatan.sh -s catatan -n banyak
printf 'kode keluar: %s\n' "$?"[ERROR] opsi -n harus berupa bilangan bulat positif, diterima: banyak
kode keluar: 2Pemanggilan ketiga menunjuk direktori sumber yang tidak ada, dengan kode keluar 1 yang membedakan kegagalan pekerjaan dari kegagalan masukan.
# menunjuk direktori sumber yang tidak ada
bash cadangkan-catatan.sh -s tidak-ada
printf 'kode keluar: %s\n' "$?"[ERROR] direktori sumber tidak ada: tidak-ada
kode keluar: 1Tiga mode kegagalan yang diuji di atas melengkapi dua sisanya yang sudah tercakup dalam rancangannya, yaitu opsi tidak dikenal yang jatuh ke cabang \? getopts dan kegagalan perintah tar yang ditangani strict mode. Pesan [ERROR] dan Penggunaan muncul dalam keluaran demo karena stderr pada sesi demo digabungkan ke keluaran standar, sedangkan pemanggil nyata dapat memisahkannya dengan redirection. Yang terpenting, seluruh penolakan terjadi sebelum satu berkas pun disentuh, sehingga kegagalan tidak pernah meninggalkan arsip setengah jadi.
Audit shellcheck#
Skrip proyek diaudit dengan shellcheck yang sudah dibahas pada topik shellcheck, dan hasil yang diharapkan adalah tidak ada temuan sama sekali. Audit dijalankan ulang setiap kali skrip disunting, karena perbaikan kecil yang ceroboh dapat menimbulkan peringatan baru.
# mengaudit skrip proyek dengan shellcheck
shellcheck cadangkan-catatan.sh && echo "temuan: tidak ada"temuan: tidak adashellcheck adalah linter, yakni alat yang membaca kode tanpa menjalankannya untuk menemukan pola yang berisiko, sehingga auditnya cepat dan dapat diulang kapan pun. Pola shellcheck skrip.sh && echo sengaja dipilih agar keberhasilan audit tercetak tegas, karena shellcheck yang bersih mencetak keluaran kosong, dan kosongnya keluaran mudah tertukar dengan audit yang tidak berjalan. Skrip lolos audit berarti tidak ada variabel tanpa kutip, tidak ada ekspansi yang tidak diinginkan, dan tidak ada kebiasaan lama yang berisiko. Kebiasaan ini murah dilakukan pada proyek kecil, sedangkan proyek besar biasanya menjalankannya otomatis pada setiap perubahan.
Dokumentasi proyek#
Dokumentasi proyek kecil yang paling sering dibaca adalah kepala berkas skripnya, sehingga bagian paling atas cadangkan-catatan.sh berisi satu paragraf tujuan, satu contoh pemanggilan, dan daftar prasyarat. Dokumentasi semacam ini ikut terlihat setiap kali skrip dibuka, tidak pernah tertinggal, dan menjadi rujukan tercepat saat skrip diubah setelah beberapa bulan.
#!/usr/bin/env bash
# cadangkan-catatan.sh — cadangan berkala untuk direktori catatan teks
#
# Skrip ini mengemas satu direktori catatan menjadi arsip tar.gz bernomor
# urut, menjaga jumlah cadangan agar tidak melebihi batas tertentu, dan
# mencatat setiap langkah ke log. Contoh pemakaian:
#
# ./cadangkan-catatan.sh -s catatan -d cadangan -n 3
#
# Prasyarat: bash, tar, gzip, dan find.Dokumentasi kedua adalah opsi -h yang mencetak pesan penggunaan, sehingga pemanggil yang lupa antarmukanya dapat melihat ringkasannya langsung dari skrip tanpa membuka kodenya. Karena -h dan setiap pesan error memanggil fungsi penggunaan yang sama, teks bantuan hanya ada satu salinan dan tidak mungkin berbeda antartempat. Di dalam badan skrip, komentar pemisah per bagian seperti penanda rotasi membuat lompatan pembacaan lebih cepat, sehingga dokumentasi dan kode saling menuntun.
# membaca dokumentasi ringkas lewat opsi -h
bash cadangkan-catatan.sh -hPenggunaan: cadangkan-catatan.sh -s direktori_sumber [-d direktori_cadangan] [-n jumlah_maksimum] [-h]Berkas skrip yang tersimpan di samping artikel ini sudah diberi izin eksekusi, sehingga pada mesin sendiri cukup satu kali chmod +x cadangkan-catatan.sh lalu skrip dipanggil sebagai ./cadangkan-catatan.sh. Penjadwalan agar pencadangan berjalan otomatis pada waktu tertentu dibahas pada topik cron dan penjadwalan, dan pemanggilan manual seperti pada demo di atas tetap menjadi dasar sebelum skrip dipasangkan dengan penjadwal.
Ringkasan#
- Skrip utuh menyusun fungsi pesan, penguraian opsi, validasi, penomoran, pengemasan, dan rotasi sesuai diagram rancangan.
- Demo utama membuktikan arsip bernomor, isi arsip yang benar, dan rotasi yang menghapus arsip tertua dengan nomor yang tetap melanjutkan deret.
- Mode kegagalan teruji dengan kode keluar 2 untuk masukan yang salah dan 1 untuk pekerjaan yang gagal.
- shellcheck menemukan nol temuan, sedangkan dokumentasi berada di kepala berkas skrip dan di opsi
-h.
Referensi#
- GNU Bash Reference Manual — Free Software Foundation — Manual resmi bash untuk strict mode, getopts, trap, dan array yang dipakai skrip proyek.
- ShellCheck — shell script analysis tool — Alat audit yang menemukan kesalahan umum skrip shell, dipakai untuk memastikan skrip proyek bersih.
- GNU tar Manual — Free Software Foundation — Manual GNU tar untuk opsi pengemasan dan pemeriksaan arsip pada skrip proyek.
- GNU gzip Manual — Free Software Foundation — Manual GNU gzip untuk kompresi yang menyertai opsi z pada tar.