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…

Globbing & Brace Expansion

Shell melakukan banyak ekspansi pada sebuah perintah sebelum dijalankan. Dua yang paling berguna sehari-hari: glob (match nama file) dan brace expansion (generate string).

Glob Patterns Dasar

Glob bukan regex — sintaksnya lebih sederhana, khusus untuk match nama file:

Pattern Arti Contoh match
* Nol atau lebih karakter apa pun *.jsapp.js, util.js
? Tepat satu karakter file?.txtfile1.txt, fileA.txt
[abc] Salah satu dari a, b, atau c [tT]est.jstest.js, Test.js
[a-z] Range karakter [0-9]*.log1.log, 2024.log
[!abc] / [^abc] BUKAN a, b, atau c [!_]*.md → semua .md kecuali yang diawali _
ls *.js                # semua file .js
ls src/*.{js,ts}       # js dan ts di src
ls [A-Z]*              # file yang dimulai huruf kapital
ls test?.log           # test1.log, testA.log (tepat 1 karakter)
ls [!.]*               # semua file yang TIDAK dimulai titik

Extglob — Glob Extended

Bash menyediakan pattern lebih kuat via shopt -s extglob:

shopt -s extglob   # aktifkan (biasanya sudah aktif di zsh)

ls ?(pattern)      # 0 atau 1 kali   → file, files
ls *(pattern)      # 0 atau lebih    → (mirip *)
ls +(pattern)      # 1 atau lebih    → minimal 1
ls @(a|b|c)        # tepat satu dari → a, b, atau c
ls !(pattern)      # apa pun KECUALI pattern
ls !(node_modules)           # semua kecuali node_modules
ls *.@(jpg|png|gif)          # gambar saja
ls +([0-9]).txt              # file yang nama-nya hanya angka
rm !(*.md|*.txt)             # hapus semua kecuali md dan txt

Recursive Glob (**)

Untuk match file di semua subdirektori sekaligus:

# Bash: aktifkan globstar dulu
shopt -s globstar

ls **/*.js                   # semua .js rekursif
grep "TODO" **/*.py          # cari TODO di semua .py

Brace Expansion

Berbeda dari glob, brace expansion men-generate string — tidak peduli file-nya ada atau tidak.

echo {a,b,c}                 # a b c
echo img.{jpg,png,gif}       # img.jpg img.png img.gif

# Range angka
echo {1..5}                  # 1 2 3 4 5
echo {10..1}                 # 10 9 8 7 ... 1 (reverse)
echo {1..10..2}              # 1 3 5 7 9 (step 2)

# Zero-padded
echo {01..05}                # 01 02 03 04 05
echo {001..100}              # 001 002 ... 100

# Range huruf
echo {a..e}                  # a b c d e

# Nested braces
echo {a,b}-{1,2}             # a-1 a-2 b-1 b-2
mkdir -p project/{src,tests,docs}/{js,css}
# → project/src/js, project/src/css, project/tests/js, ...

Brace expansion + glob sangat kuat:

# Backup file konfigurasi
cp config.json{,.bak}
# → cp config.json config.json.bak  (comma kosong = "" di ujung)

# Batch rename (lewat mv + brace)
mv foto-{01..10}.jpg arsip/

# Buat 5 file log kosong
touch log-{1..5}.txt

# Copy pattern
cp app.{html,css,js} dist/

Urutan Ekspansi (Penting!)

Shell meng-expand dalam urutan tetap — paham urutan ini menjelaskan banyak perilaku membingungkan:

<style> .step { fill: #fef3c7; stroke: #b45309; stroke-width: 1.5; } .step-num { fill: #b45309; font: 700 18px ui-sans-serif, system-ui; } .step-name { fill: #111827; font: 600 14px ui-sans-serif, system-ui; } .step-desc { fill: #374151; font: 500 11px ui-sans-serif, system-ui; } .arrow { stroke: #6b7280; stroke-width: 2; fill: none; } .arrow-head { fill: #6b7280; } </style> 1 Brace expansion {a,b,c}, {1..10} — generate string, dilakukan paling awal 2 Tilde expansion ~ → $HOME, ~user → home dari user itu 3 Parameter / Variable expansion $VAR, ${VAR:-default}, ${VAR/old/new} 4 Command substitution $(cmd) dan `cmd` — jalankan dulu, hasilnya masuk ke command line 5 Arithmetic expansion $((2+3)), $((i*2)) — evaluasi ekspresi matematika 6 Word splitting Pecah string tanpa quote berdasar $IFS (default: spasi/tab/newline) 7 Pathname / glob expansion *, ?, [abc], ** — match nama file yang benar-benar ada

Konsekuensi:

# Brace (1) dulu, baru glob (7) — jadi brace JALAN walau file tidak ada
echo file.{jpg,png}          # → file.jpg file.png (tetap walau file tidak ada)

# Glob (7) paling akhir — kalau tidak ada match, pattern tetap literal
ls *.tidak-ada-extension     # ls: *.tidak-ada-extension: No such file or directory

# Variable (3) sebelum glob (7)
FILES="*.js"
ls $FILES                    # $FILES di-expand ke *.js, lalu glob match

Quoting — Mematikan Ekspansi

echo "File: $USER"           # File: budi
echo 'File: $USER'         # File: $USER (literal)
echo {1..3}                  # 1 2 3
echo "{1..3}"                # {1..3}  (brace mati di dalam ")

Tips

  1. Test dulu dengan echo — sebelum rm atau mv, jalankan echo untuk lihat hasil ekspansi.
  2. Gunakan brace untuk batch operasimv foto-{01..20}.jpg arsip/ jauh lebih singkat dari loop.
  3. Aktifkan globstar di ~/.bashrc agar ** berfungsi — shopt -s globstar.
  4. Kutip variabel yang mungkin berisi spasi"$filename" bukan $filename.

Yang akan kamu pelajari