Membongkar kekuatan globbing Zsh yang legendaris: recursive glob **/, brace expansion {c,h}, negasi ^, ekstensi glob qualifiers seperti (#i), dan pola pengecualian *.txt~excl.txt, ditambah parameter expansion lanjutan dan command substitution yang membuat pola file menjadi lebih ekspresif daripada bash

Setelah di episode 4 kalian memahami sintaks dasar dan perbedaan Zsh vs bash, pada episode ini kita membahas topik yang membuat Zsh legendaris: globbing dan expansions. Kemampuan Zsh dalam memanipulasi pola nama file adalah salah satu alasan utama para power user beralih dari bash — dan memahami ini akan mengubah cara kalian bekerja dengan file di terminal.
Di bash, globbing sederhana (*, ?, []) sudah terasa terbatas. Zsh menambahkan recursive glob, brace expansion, negasi, dan qualifier sehingga pola file menjadi hampir seperti bahasa pencarian mini. Combine dengan parameter expansion, dan kalian bisa menulis satu baris yang di bash butuh sepuluh baris script.
Sebagian besar fitur globbing ekstensif Zsh tersedia setelah opsi extendedglob diaktifkan. Aktifkan di .zshrc atau sesi saat ini:
setopt extendedglobTanpa opsi ini, operator seperti ^ dan ~ dianggap karakter biasa. Setelah aktif, mari kita praktikkan.
Operator ** merekursi ke dalam subdirektori — jauh lebih berguna daripada find untuk banyak kasus:
ls **/*.mdPerintah di atas mencari semua file .md di direktori saat ini dan semua subdirektorinya. Bandingkan dengan perintah find yang lebih panjang. Kita bisa menambahkan qualifier (.) untuk hanya file biasa, bukan direktori:
ls **/*.md(.) # hanya file, bukan direktori
ls **/*.md(.Lm+10) # hanya file lebih besar dari 10 MB{a,b,c}Brace expansion menghasilkan beberapa string sekaligus dan bisa dikombinasikan dengan glob:
touch file.{txt,md,log} # file.txt file.md file.log
ls *.{c,h} # semua file .c dan .h
cp app.{js,bak} # salin app.js ke app.bak
echo {1..5} # 1 2 3 4 5 (range numerik)Perhatikan bahwa {1..5} menghasilkan 1 sampai 5 tanpa perulangan manual — fitur yang sangat dipakai untuk membuat banyak file atau menjalankan loop cepat.
Operator ^ mengecualikan pola tertentu dari hasil glob:
ls ^*.log # semua file KECUALI *.log
ls *.(txt|md)^* # tidak valid — pakai syntax benar
ls *.(txt|md) # semua file .txt ATAU .md (kombinasi)Untuk "semua file kecuali beberapa", gunakan eksklusi dengan ~ (dibahas berikutnya) atau kombinasi pola. Pola paling berguna:
ls ^(*.log|*.tmp) # semua kecuali .log dan .tmpOperator ~ mengecualikan pola yang mengikutinya — sangat cocok untuk "sebagian besar, tapi tidak ini":
ls *.txt~excl.txtPerintah di atas: semua file .txt kecuali excl.txt. Ini jauh lebih singkat daripada menuliskan seluruh daftar.
ls **/*~**/*.git* # semua file, kecuali yang mengandung .gitZsh memperluas set operator pattern matching melampaui bash:
| Operator | Arti | Contoh |
|---|---|---|
**/ | Rekursif ke subdirektori | ls **/config |
(#i) | Case-insensitive | ls (#i)*.md |
[^...] | Negasi dalam set karakter | ls [^a-c]* |
a~b | A kecuali B | ls *.txt~x.txt |
(#l)pat | Ganti match dengan lowercase | jarang dipakai |
ls (#i)readme*
# cocok: readme.md, README.md, ReadMe.txtIni sangat berguna di file system yang peka huruf besar/kecil seperti Linux.
Kita sudah lihat sebagian di episode 4. Lengkapi dengan pola manipulation:
file="src/main.rs"
echo ${file#*/} # main.rs (hapus prefix terpendek "*/")
echo ${file##*/} # main.rs (hapus prefix terpanjang "*/")
echo ${file%/*} # src (hapus suffix terpendek "/*")
echo ${file%%/*} # src (hapus suffix terpanjang "/*")
name="devan"
echo ${name:l} # devan (lowercase)
echo ${(U)name} # DEVAN (uppercase via flag)Perbedaan # (terpendek) vs ## (terpanjang): ###*/? Coba dengan path lebih dalam — ${x##*/} mengambil nama file terakhir dari path, sedangkan ${x#*/} hanya menghapus satu segmen. Ini pola yang sangat sering dipakai di skrip deploy.
Command substitution menjalankan perintah dan menempatkan outputnya sebagai bagian dari perintah lain:
echo "Hari ini: $(date +%A)"
files=$(ls *.txt)
echo "Jumlah file: ${(w)#files}"Zsh menambah fitur yang tidak ada di bash: flag modifier dalam substitution, seperti ${(w)#files} yang menghitung jumlah kata. Ada juga ${(L)var} untuk lowercase, ${(U)var} untuk uppercase, dan masih banyak lagi.
Qualifier adalah fitur paling unik Zsh — ia memfilter hasil glob berdasarkan properti file:
ls *(/) # hanya direktori
ls *(.) # hanya file biasa
ls *(@) # hanya symlink
ls *(mh-3) # file yang dimodifikasi dalam 3 jam terakhir
ls *(Lk+100) # file lebih besar dari 100 KB
ls *(om[1]) # file paling baru dimodifikasils -lt **/*.(js|css)(.mh-2) # file js/css diubah 2 jam terakhirsetopt extendedglob — operator ^, ~, (#i) tidak berfungsi dan dianggap literal.no matches found (lebih aman daripada bash, tapi bisa membingungkan); gunakan setopt nullglob atau nonomatch jika ingin supres.* tanpa escape di skrip remote — perbedaan shell di sisi server bisa mengubah makna pola; selalu uji dengan print -l dulu.Tip
Cara terbaik mengecek glob sebelum mengeksekusi perintah berbahaya (seperti rm): tampilkan dulu hasilnya dengan print -l atau ls -1. Misalnya print -l **/*.tmp sebelum rm -r **/*.tmp. Ini bisa menyelamatkan file kalian dari glob yang terlalu lebar.
Inti yang harus dibawa pulang:
setopt extendedglob untuk membuka operator ^, ~, (#i).**/ untuk glob rekursif; {a,b} dan {1..5} untuk brace expansion.~ untuk eksklusi, ^ untuk negasi, (#i) untuk case-insensitive.(/), (.), (om[1]) memfilter hasil berdasarkan properti file.print -l sebelum eksekusi.Di episode 6 selanjutnya kita akan membahas fitur yang paling sering disebut sebagai alasan pindah ke Zsh: completion system — inisialisasi dengan compinit, menu completion, kustomisasi gaya dengan zstyle, completion case-insensitive, pencarian partial cd /u/l/b, hingga fuzzy matching _approximate untuk mengoreksi typo. Sampai jumpa di episode 6!