Globbing & Brace Expansion — Terminal

Globbing & Brace Expansion Shell melakukan banyak ekspansi pada sebuah perintah sebelum dijalankan. Dua yang paling berguna sehari-hari: glob (match nama…

Sebelum sebuah perintah jalan, shell membaca dulu baris yang kamu ketik dan mengganti pola-pola tertentu dengan teks lain. Ini namanya ekspansi. Dua yang paling sering dipakai: glob (*.log diganti jadi daftar nama file yang cocok) dan brace expansion (foto-{01..03}.jpg diganti jadi tiga kata). Bayangkan kamu bilang ke penjaga toko, "ambilkan semua yang labelnya berakhiran .log". Penjaga (shell) yang mencari dan menyerahkan barangnya satu per satu ke kasir (program seperti ls atau rm). Kasirnya gak pernah mendengar kata "semua", dia cuma menerima barangnya.

🧪 Tebakan cepat: di folder yang gak punya satu pun file .ts, kamu menjalankan echo *.ts. Yang tercetak apa? Tebak dulu, jawabannya ada di bagian "Kalau gak ada yang cocok".

Glob: pola untuk nama file

Folder contoh kita berisi 13 file. Dua di antaranya diawali titik, jadi tersembunyi:

.env  .gitignore  app.js  catatan.txt  file1.log  file2.log  fileku.log
foto-01.jpg  foto-02.jpg  foto-03.jpg  index.html  readme.md  style.css
Pola Artinya Contoh di folder ini
* nol atau lebih karakter apa saja *.log jadi file1.log file2.log fileku.log
? tepat satu karakter file?.log jadi file1.log file2.log
[12] satu karakter dari daftar foto-0[12].jpg jadi foto-01.jpg foto-02.jpg
[a-c] satu karakter dari rentang [a-c]* jadi app.js catatan.txt
[!f] satu karakter selain yang ada di daftar [!f]* jadi semua yang gak diawali f
$ echo file?.log
file1.log file2.log
$ echo [!f]*
app.js catatan.txt index.html readme.md style.css

Shell yang menjalankan glob, bukan programnya

rm *.log gak pernah sampai ke rm dalam bentuk itu. Shell lebih dulu mengubahnya jadi rm file1.log file2.log fileku.log, baru rm jalan. Karena itu, biasakan cek dulu dengan echo: echo *.log menampilkan persis daftar yang nanti dihapus, tanpa menghapus apa pun.

Satu aturan khusus: * dan ? gak menangkap titik di awal nama. echo * mencetak 11 file dan melewatkan .env serta .gitignore. Untuk file tersembunyi, tulis titiknya: echo .* mencetak .env .gitignore (di bash 5.2 ke atas, . dan .. gak ikut).

Kalau gak ada yang cocok

Kalau glob gak menemukan satu file pun, bash membiarkan polanya apa adanya, termasuk bintangnya:

$ echo *.ts
*.ts
$ ls *.ts
ls: cannot access '*.ts': No such file or directory

Jadi echo *.ts mencetak *.ts. Itu jawaban tebakannya. ls menerima teks *.ts dan mencari file yang benar-benar bernama *.ts, makanya pesan error-nya begitu.

Kalau kamu lebih suka pola yang gak cocok langsung hilang, nyalakan shopt -s nullglob. Hati-hati: dengan nullglob, ls *.ts berubah jadi ls saja, dan malah menampilkan semua file.

Brace expansion: bikin teks, bukan cari file

Brace expansion cuma menggandakan teks. Dia gak melihat folder sama sekali, jadi hasilnya muncul walaupun filenya gak ada.

$ echo foto-{01..05}.jpg
foto-01.jpg foto-02.jpg foto-03.jpg foto-04.jpg foto-05.jpg
$ echo {app,index}.html
app.html index.html
$ echo {1..10..2}
1 3 5 7 9
Bentuk Hasil
{a,b,c} a b c, dipisah koma
{1..5} 1 2 3 4 5
{01..03} 01 02 03. Kalau salah satu ujung diawali 0, semua angka dibuat selebar yang paling panjang
{a..e} a b c d e
{1..10..2} 1 3 5 7 9, langkah 2
config.json{,.bak} config.json config.json.bak, pilihan pertamanya kosong

Pemakaian sehari-hari: mkdir -p proyek/{src,tests,docs} bikin tiga folder sekaligus, dan cp config.json{,.bak} bikin cadangan.

Brace jalan sebelum glob. echo *.{js,css} lebih dulu jadi *.js *.css, lalu tiap kata di-glob: hasilnya app.js style.css. Dan echo *.{js,ts} jadi app.js *.ts, karena *.ts gak cocok apa pun dan tetap apa adanya.

Glob bukan regex

Glob dan regex sama-sama pola, tapi aturannya beda. Glob khusus untuk nama file dan lebih sederhana. Regex untuk teks umum dan jauh lebih kuat.

Glob Regex
* karakter apa saja, berapa pun ulangi karakter sebelumnya, nol kali atau lebih
? tepat satu karakter karakter sebelumnya boleh ada boleh gak
. titik biasa karakter apa saja

Mengubah glob jadi regex: * jadi .*, ? jadi ., titik dan simbol lain di-escape, lalu kunci di awal dan akhir. Jadi *.txt setara regex ^.*\.txt$. Titiknya di-escape, makanya note_txt gak cocok, dan kuncinya bikin note.txt.bak juga gak cocok.

Bash juga punya pola tambahan kalau shopt -s extglob dinyalakan. Yang paling berguna, !(pola) artinya "semua kecuali yang cocok": ls !(node_modules|dist) menampilkan semua entri kecuali node_modules dan dist. Lalu ** menangkap folder di semua kedalaman, setelah shopt -s globstar: ls **/*.js.

⚠️ Jebakan yang sering ketemu

TL;DR: Shell mengganti pola sebelum program jalan. Glob mencocokkan nama file yang ada: * karakter apa saja, ? tepat satu, [abc] satu dari daftar, [!abc] selain itu, dan polanya harus cocok dengan seluruh nama. * dan ? gak menangkap titik di awal nama. Kalau gak ada yang cocok, polanya tetap apa adanya (kecuali shopt -s nullglob). Brace expansion bikin teks tanpa melihat folder: {a,b}, {1..3}, {01..03} dengan nol di depan, dan jalan sebelum glob. Glob bukan regex: * glob setara .* regex, titik glob itu titik biasa. !(pola) dengan extglob artinya semua kecuali pola itu. Cek dengan echo sebelum rm.

Yang akan kamu pelajari