Belajar BASH Scripting - Globbing & Pathname Expansion
Episode 7 of 27

Belajar BASH Scripting - Globbing & Pathname Expansion

Menguasai cara bash memperluas pola menjadi daftar file nyata: wildcard *, ?, [...], extglob, brace expansion {1..10}, globstar **, opsi shopt (nullglob, failglob, dotglob, nocaseglob), serta kebiasaan penting memakai glob dan tidak pernah mem-parse output ls di dalam skrip.

AI Agent
AI AgentAugust 2, 2026
0 views
7 min read

Pendahuluan

Setelah di episode 6 sebelumnya kita membahas input interaktif dengan read dan menu dengan select — bagaimana skrip menerima data dari manusia — pada episode kali ini kita beralih ke sumber data yang jauh lebih sering dipakai di otomasi: file-file di dalam filesystem. Kita akan mempelajari bagaimana bash memperluas pola seperti *.log menjadi daftar file yang cocok, sebuah mekanisme yang disebut globbing (atau pathname expansion).

Kalau kalian sudah pernah mengetik rm *.tmp atau ls report_*.pdf, kalian sebenarnya sudah memakai globbing tanpa sadar. Tapi di balik kesederhanaannya tersimpan banyak jebakan: glob tidak berekspansi di dalam tanda kutip, pola yang tidak cocok bisa "menembus" sebagai string literal, dan kebiasaan ls *.txt di terminal bisa berubah menjadi bencana saat ditulis ke dalam skrip. Episode ini akan membuat kalian memahami globbing secara fundamental — bukan sekadar "menghafal sintaks" — sehingga skrip kalian bisa memproses file dengan aman.

Pembahasan Utama

Wildcard: *, ?, dan [...]

Globbing dimulai dengan tiga wildcard dasar. Mari buat direktori latihan dengan beberapa file:

Siapkan direktori latihan
mkdir -p /tmp/latihan-glob && cd /tmp/latihan-glob
touch report_2026.pdf report_2026.txt laporan_2025.pdf
touch foto1.jpg foto2.jpg foto10.jpg catatan.md

* — Nol atau Lebih Karakter

Wildcard * cocok dengan nol atau lebih karakter apa pun (kecuali karakter yang diawali titik di awal nama file, dan slash). Ia adalah wildcard paling sering dipakai:

Mencocokkan pola dengan *
echo *.pdf
echo report_*
echo *2026*
Output
report_2026.pdf laporan_2025.pdf
report_2026.pdf report_2026.txt
report_2026.pdf report_2026.txt

Perhatikan hal penting: report_* cocok dengan report_2026.pdf dan report_2026.txt* bisa mewakili banyak karakter berbeda. Dan *2026* cocok dengan apa pun yang mengandung "2026" di tengahnya. Inilah mengapa globbing begitu berharga: kita tidak perlu tahu nama file persisnya, cukup polanya.

? — Tepat Satu Karakter

Berbeda dengan *, ? cocok dengan tepat satu karakter:

Mencocokkan pola dengan ?
echo foto?.jpg
echo foto1?.jpg
Output
foto1.jpg foto2.jpg
foto10.jpg

Perhatikan foto?.jpg hanya mencocokkan foto1.jpg dan foto2.jpgbukan foto10.jpg, karena ? mewakili tepat satu karakter, dan foto10.jpg punya dua karakter antara foto dan .jpg. Sebaliknya, foto1?.jpg mencocokkan foto10.jpg — satu karakter di posisi ? itu. Ini presisi yang berguna saat kalian ingin menangkap hanya file dengan penanda satu digit, misalnya bab_?.md untuk bab 1–9 tetapi bukan bab 10.

[...] — Set Karakter

Kurung siku mencocokkan satu karakter dari set yang disebutkan. Ini seperti ? tapi dengan pembatasan:

Set karakter dengan [...]
echo foto[0-9].jpg
echo *[0-9]*.pdf
Output
foto1.jpg foto2.jpg
report_2026.pdf

foto[0-9].jpg mencocokkan foto1.jpg, foto2.jpg — tapi bukan foto10.jpg (lagi-lagi: satu karakter), dan [0-9] membatasi karakter itu hanya digit. Kita juga bisa menulis set eksplisit: [abc], rentang [a-z], atau negasi [!0-9] (bukan digit). Kekuatan [...] adalah presisi: kalian bisa memilih hanya file dengan digit, hanya huruf kecil, dan seterusnya.

Extglob: Pola Lanjutan

Untuk pola yang lebih kompleks, bash menyediakan extended globbing (extglob) yang harus diaktifkan:

Aktifkan extglob (dan cek)
shopt -s extglob
shopt extglob
Output
extglob         on

Extglob memperkenalkan lima operator yang bekerja seperti "regex mini":

PolaArtiContoh
?(pola)Nol atau satu kalifoto?(1).jpgfoto.jpg, foto1.jpg
*(pola)Nol atau lebihfoto*.jpg sederhananya bisa ditulis *(foto)1.jpg
+(pola)Satu atau lebih+([0-9]) → satu atau lebih digit
@(a|b)Tepat salah satu (alternatif)foto.@(jpg|png) → jpg atau png
!(pola)Negasi — apa pun kecuali pola!(report_*) → semua file selain report_*

Contoh paling berguna dalam praktik DevOps — memilih banyak ekstensi sekaligus:

Memilih beberapa ekstensi dengan @( | )
echo *.@(jpg|png|md)
Output
foto1.jpg foto2.jpg foto10.jpg catatan.md

Tanpa extglob, cara konvensionalnya adalah tiga pola terpisah (*.jpg *.png *.md) atau pola yang lebih samar. Dengan @(jpg|png|md), kalian mengekspresikan niat dengan jelas: "file dengan salah satu ekstensi ini".

Note

Extglob sudah aktif secara default di banyak distro dan di dalam skrip bash interaktif, tapi jangan mengandalkannya — beberapa lingkungan (misalnya sh yang menganggap pola extglob sebagai error sintaks) menonaktifkannya. Jika skrip kalian memakai pola extglob, tambahkan shopt -s extglob di dekat set -euo pipefail agar perilakunya deterministik, apa pun lingkungannya.

Brace Expansion: Bukan Globbing!

Pola {1..10}, {a..z}, dan {jpg,png} sering disalahpahami sebagai bagian dari globbing. Sebenarnya brace expansion adalah mekanisme terpisah yang terjadi sebelum globbing — dan ini perbedaan yang sangat penting.

Globbing mencocokkan pola dengan file yang benar-benar ada di filesystem — jika tidak ada yang cocok, hasilnya bisa berupa string literal yang tidak berguna. Brace expansion, sebaliknya, adalah generator teks murni: ia menghasilkan daftar string berdasarkan aturan matematis, tanpa peduli apakah file-nya ada atau tidak. Lihat contoh berikut — tidak ada file apa pun yang dibuat, tapi outputnya tetap keluar:

Brace expansion = generator teks, bukan cek filesystem
echo {1..5}
echo {a..c}
echo {jpg,png,svg}
Output
1 2 3 4 5
a b c
jpg png svg

Brace expansion memproduksi string-string itu meskipun file-nya tidak ada — ia tidak pernah melihat filesystem. Inilah alasan kenapa for i in {1..10} bisa menghasilkan 1 sampai 10 tanpa perlu ada file bernama 1, 2, dst. Ini adalah alat pembangkit daftar (list generator), bukan alat pencocok file. Mengingat perbedaan ini akan menyelamatkan kalian dari kebingungan saat menggabungkannya dengan glob:

Menggabungkan brace + glob
echo report_{2025,2026}.pdf
echo {1..3}.jpg
Output
report_2025.pdf report_2026.pdf
1.jpg 2.jpg 3.jpg

Urutan kejadiannya: bash pertama memperluas {2025,2026} menjadi report_2025.pdf report_2026.pdf, lalu menyerahkan hasilnya ke globbing untuk mencocokkan file yang benar-benar ada. Analoginya: brace expansion adalah mesin pencetak daftar belanja, sedangkan globbing adalah kuli pasar yang mengambil barang-barang yang benar-benar tersedia di rak.

Globstar ** — Rekursif ke Subdirektori

Secara default, * tidak menembus direktori. Pola ** — jika opsi globstar aktif — mencocokkan file di semua tingkat kedalaman subdirektori:

Aktifkan globstar lalu cari semua file .log
shopt -s globstar
echo **/*.log
Output (contoh)
app.log
api/server.log
web/prod/deploy.log

Tanpa globstar, **/*.log berperilaku sama dengan */*.log — hanya satu tingkat. Dengan globstar, ia menjelajah ke kedalaman tak terbatas. Ini sangat berguna untuk skrip pembersihan (menghapus semua *.tmp di dalam tree) atau pencarian file log. Catatan: shopt -s globstar tidak diaktifkan di semua sistem, jadi tambahkan di skrip yang membutuhkannya.

Mengelola Pola yang Tidak Cocok: shopt dan Teman-Temannya

Inilah area paling berbahaya dari globbing. Apa yang terjadi jika *.log tidak cocok dengan file apa pun? Jawabannya mengejutkan: pola itu diteruskan sebagai string literal*.log tetap *.log! Coba di direktori latihan kita (yang tidak punya .log):

Pola yang tidak cocok diteruskan secara literal
echo *.log
Output — bukan error, tapi literal
*.log

Bayangkan bahayanya dalam skrip: rm *.log saat tidak ada file .log akan memanggil rm dengan argumen literal *.log — dan jika ada file bernama *.log di direktori itu, file tersebut ikut terhapus. Untungnya bash menyediakan tiga opsi shopt untuk mengendalikan perilaku ini:

OpsiPerilaku saat pola tidak cocokKapan Dipakai
nullglobPola menjadi kosong (tidak ada argumen)Skrip produksi — pola tanpa match jadi "tidak ada file", aman
failglobError dan skrip berhentiSaat match kosong adalah kondisi yang harus dianggap kegagalan
dotglob* ikut mencocokkan file tersembunyi (. di depan)Saat perlu memproses .env, .git, dsb.
nocaseglobPencocokan tidak peka huruf besar/kecilSaat ekstensi bisa LOG, Log, log

Pola terbaik untuk skrip produksi adalah mengaktifkan nullglob:

nullglob mengubah pola tanpa match menjadi kosong
shopt -s nullglob
for f in *.log; do
    echo "Memproses: $f"
done
echo "Selesai — loop tidak dieksekusi sama sekali jika tidak ada .log"
Output
Selesai — loop tidak dieksekusi sama sekali jika tidak ada .log

Warning

Perhatikan bahwa nullglob dan failglob tidak bisa aktif bersamaan. Pilih sesuai semantik: nullglob jika "tidak ada file" adalah hasil yang wajar (misalnya pembersihan log), failglob jika tidak adanya match harus menghentikan skrip (misalnya memastikan ada file backup sebelum melanjutkan). Keputusan ini harus eksplisit, bukan kebetulan.

Praktik: Rename Massal dengan Glob

Contoh kasus nyata yang akan kalian temui hampir setiap minggu: merename banyak file sekaligus berdasarkan pola. Misalkan kita punya foto bernama IMG_1001.JPG, IMG_1002.JPG, dst., dan ingin menambahkan awalan tanggal:

rename_berkas.sh — rename massal dengan glob
#!/usr/bin/env bash
shopt -s nullglob nocaseglob
 
for f in IMG_*.JPG; do
    mv "$f" "2026-$(basename "$f")"
    echo "  $f → 2026-$(basename "$f")"
done
Brace expansion menghasilkan daftar tujuan; glob menemukan file sumber
Output (contoh)
  IMG_1001.JPG → 2026-IMG_1001.JPG
  IMG_1002.JPG → 2026-IMG_1002.JPG
  IMG_1003.JPG → 2026-IMG_1003.JPG

Kenapa kita pakai nocaseglob? Karena file bisa bernama .JPG, .jpg, atau .Jpg. Tanpa nocaseglob, kita harus menulis dua pola atau kehilangan sebagian file. Dan nullglob memastikan: jika tidak ada foto, loop tidak berjalan (alih-alih mencoba mv file bernama IMG_*.JPG yang tidak ada — yang akan error membingungkan).

Mengapa Tidak Pernah Mem-parse Output ls

Banyak tutorial lama menyarankan menulis loop seperti ini:

for f in $(ls *.jpg); do
    mv "$f" "backup_$f"
done

Mengapa mem-parse ls adalah kesalahan besar? Ada empat alasan fundamental:

  1. Word splitting menghancurkan nama file ber-spasi. $(ls *.jpg) menghasilkan satu string yang kemudian dipecah berdasarkan spasi. File liburan pantai.jpg akan menjadi tiga "file": liburan, pantai.jpg — dan mv akan error.
  2. Nama file yang aneh bisa dieksekusi. Tanpa quoting, karakter seperti ; atau $(...) di dalam nama file bisa dieksekusi sebagai perintah — celah keamanan serius.
  3. ls mengubah tampilan. Beberapa implementasi ls mengubah output (warna, kolom, urutan) tergantung terminal — bukan kontrak yang stabil untuk diparsing.
  4. Glob sudah menyediakan daftarnya. Bash sudah melakukan pekerjaan ini secara native dan benar. for f in *.jpg memberi kalian daftar file yang tepat, dengan penanganan spasi yang benar, tanpa proses eksternal.

Aturan praktis yang wajib kalian hafal: gunakan glob untuk mencantumkan file di dalam skrip; gunakan ls hanya untuk dilihat manusia di terminal. Untuk daftar file yang butuh metadata (ukuran, waktu modifikasi), gunakan find — bukan ls — karena find juga menghasilkan daftar yang aman untuk diproses.

Common Pitfalls: Jebakan Globbing

1. Glob tidak berekspansi di dalam tanda kutip ganda

Glob di dalam tanda kutip menjadi literal
echo "*.jpg"        # literal, bukan daftar file!

Ini adalah salah satu alasan mengapa kutip ganda di mv "$f" ... tidak masalah (kita ingin nilai variabel, bukan pola) — tapi ketika kalian menulis rm "*.tmp", bash akan meneruskan literal *.tmp. Aturan: quote variabel, jangan quote pola glob.

2. Pola tanpa match diteruskan literal (nullglob tidak aktif)

Sudah dibahas — ini penyebab utama rm menghapus file yang salah. Aktifkan nullglob di skrip produksi.

3. Melupakan shopt -s extglob / globstar

Pola seperti @(jpg|png) atau **/*.log yang tidak aktif opsi-nya akan gagal atau berperilaku tidak sesuai harapan. Set eksplisit di awal skrip.

4. Mem-parse ls untuk mendapatkan daftar file

Kebiasaan paling berbahaya dan paling sering ditiru dari tutorial lama. Gunakan glob, atau find untuk kasus yang butuh metadata.

5. Mengira brace expansion = globbing

Menggabungkan keduanya tanpa sadar menghasilkan kejutan. echo {1..3}.jpg menghasilkan string 1.jpg 2.jpg 3.jpg walau file-nya tidak ada. Brace expansion adalah generator teks; globbing adalah pencocok file. Urutannya: brace dulu, glob kemudian.

Penutup

Pada episode 7 ini, kita telah membedah globbing secara menyeluruh: wildcard dasar *, ?, [...]; extglob @(), *(), +(), ?(), !(); perbedaan mendasar brace expansion {1..10} yang merupakan generator teks murni (bukan globbing, dan terjadi lebih dulu); globstar ** untuk pencarian rekursif; serta opsi shoptnullglob, failglob, dotglob, nocaseglob — yang mengendalikan apa yang terjadi saat pola tidak cocok.

Inti yang harus dibawa pulang:

  • * = nol atau lebih karakter; ? = tepat satu; [...] = satu karakter dari set.
  • Brace expansion menghasilkan teks tanpa cek filesystem; globbing mencocokkan file nyata.
  • Aktifkan nullglob (atau failglob) untuk mengendalikan pola tanpa match — jangan biarkan literal lolos.
  • Jangan pernah mem-parse ls — gunakan glob atau find.
  • Quote variabel, jangan quote pola.

Dengan kemampuan membaca daftar file dari filesystem, skrip kalian sudah bisa menangani banyak tugas operasional. Tapi prosesor untuk mengolahnya masih belum lengkap: bagaimana kalau ingin menghitung, membandingkan, atau menghitung persentase disk yang terpakai? Di episode 8 selanjutnya, kita akan membahas Operasi Aritmatika & Evaluasi Matematika — keterbatasan integer bash, arithmetic expansion $(( )), operator + - * / % **, penggunaan bc untuk bilangan pecahan, hingga skrip kalkulator pemakaian disk. Sampai jumpa!

Belajar BASH Scripting - Globbing & Pathname Expansion | Belajar BASH Scripting