Perintah `which` di Linux: Panduan Teknis Lengkap dengan Contoh
Perintah `which` di Linux menemukan jalur absolut dari sebuah executable dengan memindai direktori yang tercantum dalam variabel lingkungan `PATH` dan mengembalikan kecocokan pertama yang ditemukan. Ini adalah utilitas yang berdekatan dengan POSIX yang digunakan setiap hari oleh administrator sistem, pengembang, dan insinyur DevOps untuk memverifikasi lokasi biner, mengaudit lingkungan eksekusi, dan men-debug konflik terkait PATH.
Ketika Anda menjalankan `which python3`, shell tidak mencari seluruh filesystem — ia hanya melintasi daftar direktori yang dipisahkan titik dua yang tersimpan di `$PATH`, dari kiri ke kanan, dan berhenti pada kecocokan pertama. Perilaku ini sekaligus menjadi kekuatan terbesarnya dan keterbatasan terpentingnya yang perlu dipahami.
Sintaks Dasar
“`bash
which [options] command_name [command_name …]
“`
- `[options]` — Flag opsional yang mengubah perilaku output (dibahas secara rinci di bawah).
- `command_name` — Satu atau lebih nama executable yang ingin Anda temukan.
Cara Kerja `which` Secara Internal
Ketika Anda memanggil `which`, ia membaca nilai saat ini dari variabel lingkungan `PATH`, memisahkannya pada pembatas `:`, dan mengiterasi setiap direktori secara berurutan. Untuk setiap direktori, ia memeriksa apakah file yang cocok dengan nama perintah ada dan memiliki bit executable yang disetel (izin `x`). Kecocokan pertama dicetak ke output standar.
Ini berarti `which` sepenuhnya bergantung pada status runtime dari `$PATH`. Jika `PATH` Anda salah dikonfigurasi — misalnya, direktori kustom muncul setelah `/usr/bin` alih-alih sebelumnya — `which` akan mencerminkan kesalahan konfigurasi tersebut dengan tepat, yang justru itulah mengapa berguna untuk debugging.
Untuk memeriksa `PATH` Anda saat ini:
“`bash
echo $PATH
Example output:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
“`
Kasus Penggunaan Utama dan Contoh
Contoh 1: Menemukan Satu Executable
Penggunaan paling mendasar adalah menemukan di mana sebuah biner berada:
“`bash
which python3
“`
“`
/usr/bin/python3
“`
Ini mengonfirmasi bahwa ketika Anda mengetik `python3`, sistem mengeksekusi `/usr/bin/python3`. Jika Anda telah mengompilasi build kustom dan menempatkannya di `/opt/python3.12/bin/`, tetapi direktori tersebut tidak ada di `PATH`, `which` tidak akan menemukannya.
Contoh 2: Menanyakan Beberapa Perintah Sekaligus
Anda dapat meneruskan beberapa nama perintah dalam satu pemanggilan, yang efisien saat mengaudit lingkungan build:
“`bash
which python3 gcc git curl wget
“`
“`
/usr/bin/python3
/usr/bin/gcc
/usr/bin/git
/usr/bin/curl
/usr/bin/usr/bin/wget
“`
Ini sangat berguna dalam skrip validasi pipeline CI/CD, di mana Anda perlu mengonfirmasi bahwa semua alat yang diperlukan tersedia sebelum build dimulai.
Contoh 3: Menemukan Semua Instans dengan `-a`
Flag `-a` menginstruksikan `which` untuk terus mencari setelah kecocokan pertama dan melaporkan setiap instans yang ditemukan di seluruh direktori `PATH`:
“`bash
which -a python3
“`
“`
/usr/bin/python3
/usr/local/bin/python3
“`
Ini sangat penting di lingkungan di mana beberapa versi Python terinstal — misalnya, Python sistem di `/usr/bin/python3` dan versi yang dikelola pyenv di `/usr/local/bin/python3`. Biner yang muncul pertama di `PATH` adalah yang akan dieksekusi. Jika versi yang salah aktif, output ini memberi tahu Anda dengan tepat di mana konflik berasal.
Kasus tepi dunia nyata: Pada server yang menjalankan Node.js yang dikemas distribusi dan Node.js yang dikelola nvm, `which -a node` sering kali mengungkapkan dua atau tiga jalur yang bertentangan. Menyelesaikan ini memerlukan pengurutan ulang entri `PATH` di `.bashrc` atau `.zshrc`, bukan menginstal ulang perangkat lunak.
Contoh 4: Perilaku Resolusi Alias
Perilaku `which` dengan alias sangat bergantung pada shell dan implementasi spesifik dari `which` yang terinstal di sistem.
Pada banyak distribusi Linux, `which` adalah biner eksternal mandiri (bukan built-in shell), sehingga tidak memiliki akses ke tabel alias shell saat ini. Namun, pada sistem di mana `which` diimplementasikan sebagai fungsi shell atau alias itu sendiri (umum dalam konfigurasi zsh), ia mungkin dapat meresolvasi alias:
“`bash
alias ls='ls –color=auto'
which ls
“`
Pada sistem zsh dengan `which` berbasis fungsi:
“`
ls: aliased to ls –color=auto
“`
Pada sistem bash dengan biner eksternal `which`:
“`
/bin/ls
“`
Ketidakkonsistenan ini adalah sumber kebingungan yang sudah dikenal dan merupakan salah satu alasan utama administrator berpengalaman lebih memilih `type` atau `command -v` dalam skrip (dibahas di bawah).
Contoh 5: Menggunakan `which` dalam Logika Skrip Kondisional
Pola umum dalam skrip shell adalah menggunakan `which` untuk memeriksa dependensi sebelum melanjutkan:
“`bash
if ! which docker > /dev/null 2>&1; then
echo "Docker is not installed or not in PATH. Aborting."
exit 1
fi
“`
Namun, pendekatan yang lebih portabel dan sesuai POSIX untuk skrip adalah `command -v`:
“`bash
if ! command -v docker > /dev/null 2>&1; then
echo "Docker not found."
exit 1
fi
“`
Perbedaan ini penting saat menulis skrip yang dimaksudkan untuk berjalan di berbagai distribusi atau shell.
`which` vs. `type` vs. `command -v`: Perbandingan Teknis
Ketiga alat ini menangani kebutuhan yang tumpang tindih tetapi berbeda. Memilih yang salah untuk pekerjaan tersebut menyebabkan bug yang halus, terutama dalam skrip shell.
| Fitur | `which` | `type` | `command -v` |
|---|
| — | — | — | — |
|---|
| Menemukan biner eksternal | Ya | Ya | Ya |
|---|
| Meresolvasi alias shell | Bergantung pada implementasi | Ya (selalu) | Ya (selalu) |
|---|
| Meresolvasi fungsi shell | Tidak | Ya | Ya |
|---|
| Mengidentifikasi built-in shell | Tidak | Ya | Ya |
|---|
| Sesuai POSIX | Tidak | Ya | Ya |
|---|
| Bekerja dengan andal dalam skrip | Berisiko | Berisiko (built-in bash) | Direkomendasikan |
|---|
| Format output | Hanya jalur | String deskriptif | Jalur atau definisi |
|---|
| Mencari semua entri PATH (setara `-a`) | Ya (dengan `-a`) | Ya (dengan `-a`) | Tidak |
|---|
| Biner eksternal (bukan built-in) | Ya | Tidak (built-in) | Tidak (built-in) |
|---|
Panduan praktis:
- Gunakan `which` secara interaktif di terminal ketika Anda membutuhkan pencarian jalur cepat.
- Gunakan `type -a` ketika Anda ingin melihat setiap bentuk yang diambil suatu perintah (alias, fungsi, built-in, dan biner).
- Gunakan `command -v` dalam skrip shell produksi untuk portabilitas POSIX.
`type` dalam Aksi
“`bash
type -a python3
“`
“`
python3 is /usr/bin/python3
python3 is /usr/local/bin/python3
“`
“`bash
type ls
“`
“`
ls is aliased to `ls –color=auto'
“`
`command -v` dalam Aksi
“`bash
command -v git
“`
“`
/usr/bin/git
“`
“`bash
command -v ll
“`
“`
ll: aliased to ls -alF
“`
Skenario Debugging Praktis
Men-debug Versi Python yang Salah
Seorang pengembang melaporkan bahwa `python3 –version` mengembalikan `3.9.x` tetapi mereka menginstal `3.11` melalui build kustom. Urutan diagnostiknya:
“`bash
which python3 # Shows the first match
which -a python3 # Shows all matches
echo $PATH # Reveals directory ordering
ls -la /usr/local/bin/python3 # Checks if the custom build is symlinked correctly
“`
Perbaikannya hampir selalu berupa symlink yang hilang atau masalah pengurutan `PATH` dalam file inisialisasi shell.
Mendiagnosis Perintah yang Hilang Setelah Instalasi
Jika `which curl` tidak menghasilkan output, biner tersebut tidak terinstal atau terinstal ke direktori non-`PATH`. Bedakan antara kasus-kasus ini:
“`bash
which curl # No output = not in PATH
find /usr -name curl -type f 2>/dev/null # Search for the binary outside PATH
apt list –installed 2>/dev/null | grep curl # Check package manager
“`
Memverifikasi Jalur Alat Sebelum Deployment
Saat mengonfigurasi lingkungan VPS Hosting baru, daftar periksa pra-deployment standar harus mencakup menjalankan `which -a` terhadap setiap biner kritis yang bergantung pada aplikasi Anda. Ini menangkap penyimpangan lingkungan antara pengembangan, staging, dan produksi sebelum menyebabkan kegagalan runtime.
Keterbatasan yang Diketahui dari `which`
Memahami keterbatasan ini mencegah kesalahan diagnosis di lingkungan yang kompleks:
- Cakupan hanya `PATH`: `which` tidak dapat melihat executable apa pun yang tidak dapat dijangkau melalui `$PATH`. Alat yang terinstal di direktori lokal pengguna seperti `~/.local/bin` hanya akan ditemukan jika direktori tersebut ada di `PATH`.
- Tidak mengetahui built-in shell: Perintah seperti `cd`, `echo`, `alias`, dan `source` adalah built-in shell. `which cd` akan mengembalikan tidak ada atau jalur ke biner `cd` eksternal yang jarang digunakan, memberikan hasil yang menyesatkan.
- Tabel alias khusus shell: `which` sebagai biner eksternal tidak dapat membaca tabel alias dari shell yang memanggilnya. Ini membuatnya tidak dapat diandalkan untuk introspeksi alias di bash.
- Transparansi symlink: `which` melaporkan jalur symlink, bukan target yang diresolvasi. Jika `/usr/bin/python3` adalah symlink ke `/usr/bin/python3.11`, `which python3` menampilkan `/usr/bin/python3`. Gunakan `readlink -f $(which python3)` untuk meresolvasi rantai penuh.
- Konteks `sudo`: Menjalankan perintah dengan `sudo` menggunakan `PATH` milik root, yang mungkin berbeda secara signifikan dari `PATH` pengguna Anda. `which node` sebagai pengguna biasa mungkin mengembalikan jalur yang berbeda dari `sudo which node`.
Pola Lanjutan
Meresolvasi Rantai Symlink Penuh
“`bash
readlink -f $(which python3)
Output: /usr/bin/python3.11
“`
Memeriksa Izin Executable Bersama Jalur
“`bash
ls -la $(which nginx)
Output: -rwxr-xr-x 1 root root 1234567 Jan 10 2024 /usr/sbin/nginx
“`
Kombinasikan dengan `xargs` untuk Inspeksi Batch
“`bash
echo "python3 gcc git" | xargs -n1 which
“`
Gunakan dalam Skrip Validasi Lingkungan
Pada Dedicated Server yang menjalankan tumpukan aplikasi yang kompleks, skrip validasi startup mungkin terlihat seperti ini:
“`bash
#!/bin/bash
REQUIRED_BINS="nginx php-fpm mysql redis-cli composer"
MISSING=0
for bin in $REQUIRED_BINS; do
if ! command -v "$bin" > /dev/null 2>&1; then
echo "MISSING: $bin"
MISSING=$((MISSING + 1))
else
echo "OK: $bin -> $(which $bin)"
fi
done
[ "$MISSING" -gt 0 ] && exit 1
exit 0
“`
Catatan Perilaku Khusus Shell
Perilaku `which` tidak seragam di semua lingkungan Linux:
- Bash: `which` biasanya adalah biner eksternal (`/usr/bin/which`). Ia tidak melihat alias atau fungsi bash kecuali diekspor.
- Zsh: Banyak konfigurasi zsh menyertakan `which` sebagai fungsi shell built-in yang memang meresolvasi alias dan fungsi, membuat outputnya lebih kaya tetapi juga berbeda dari perilaku bash.
- Fish shell: Fish memiliki padanan `which` bawaan sendiri, dan sistem aliasnya (disebut `functions`) ditangani secara berbeda.
- Alpine Linux / lingkungan BusyBox: Utilitas `which` disediakan oleh BusyBox dan mungkin memiliki set fitur yang lebih terbatas dibandingkan paket GNU `which`.
Variabilitas ini sangat relevan saat mengelola aplikasi yang dikontainerisasi atau mengonfigurasi VPS Control Panels di mana shell yang mendasarinya mungkin berbeda dari lingkungan pengembangan lokal Anda.
Pertimbangan Keamanan
Di lingkungan yang sensitif terhadap keamanan, `which` dapat digunakan sebagai alat audit ringan:
- Verifikasi bahwa biner yang memiliki hak istimewa seperti `sudo`, `su`, atau `passwd` meresolvasi ke jalur sistem yang diharapkan dan bukan ke direktori yang dapat ditulis pengguna yang lebih awal di `PATH`.
- Deteksi upaya pembajakan PATH: jika `which ls` mengembalikan `/home/user/bin/ls` alih-alih `/bin/ls`, biner berbahaya mungkin telah disuntikkan.
“`bash
Audit critical system binaries
for cmd in sudo su passwd ssh scp; do
echo "$cmd -> $(which $cmd)"
done
“`
Ini adalah langkah standar saat mengeraskan server yang akan meng-host SSL Certificates atau menangani terminasi TLS yang sensitif, di mana integritas biner tidak dapat dikompromikan.
Saat mengelola lingkungan Shared Web Hosting dengan banyak pengguna, memverifikasi bahwa direktori yang dapat ditulis pengguna tidak muncul sebelum direktori sistem di `PATH` pengguna mana pun adalah kontrol keamanan yang penting.
Matriks Keputusan: Kapan Menggunakan Alat Mana
| Skenario | Alat yang Direkomendasikan |
|---|
| — | — |
|---|
| Pencarian jalur interaktif cepat | `which` |
|---|
| Skrip: periksa apakah perintah ada | `command -v` |
|---|
| Identifikasi apakah perintah adalah alias atau fungsi | `type` |
|---|
| Temukan semua instans di seluruh PATH | `which -a` atau `type -a` |
|---|
| Resolvasi symlink ke biner akhir | `readlink -f $(which …)` |
|---|
| Audit untuk pembajakan PATH | `which` + inspeksi PATH manual |
|---|
| Skrip portabel lintas shell | `command -v` |
|---|
Poin Penting Teknis
- `which` mencari `$PATH` dari kiri ke kanan dan mengembalikan kecocokan executable pertama — urutan entri `PATH` secara langsung menentukan biner mana yang dijalankan.
- Flag `-a` sangat penting ketika beberapa versi alat ada berdampingan; jangan pernah berasumsi hanya ada satu instans tanpa memeriksa.
- Jangan gunakan `which` dalam skrip shell produksi — gunakan `command -v` untuk kepatuhan POSIX dan perilaku yang konsisten di seluruh bash, dash, dan zsh.
- `which` tidak dapat melihat built-in shell, fungsi, atau alias yang didefinisikan dalam sesi shell saat ini ketika berjalan sebagai biner eksternal.
- Selalu tindak lanjuti hasil `which` dengan `readlink -f` ketika symlink terlibat untuk mengidentifikasi biner aktual yang sedang dieksekusi.
- Di lingkungan multi-pengguna atau yang dikontainerisasi, `PATH` berbeda antar pengguna dan antara konteks `sudo` dan non-`sudo` — selalu verifikasi dalam konteks yang benar.
- Pembajakan PATH melalui direktori yang dapat ditulis pengguna yang ditambahkan di depan `$PATH` adalah vektor serangan nyata; `which` adalah alat audit lini pertama yang cepat untuk menghadapinya.
Pertanyaan yang Sering Diajukan
Apa perbedaan antara `which` dan `whereis`?
`which` hanya mencari `$PATH` untuk executable. `whereis` mencari sekumpulan direktori sistem yang telah ditentukan sebelumnya untuk biner, halaman manual, dan file sumbernya secara bersamaan. Gunakan `whereis` ketika Anda perlu menemukan dokumentasi atau sumber bersama biner.
Mengapa `which cd` tidak mengembalikan apa pun?
`cd` adalah built-in shell, bukan executable eksternal. Karena `which` hanya memindai `$PATH` untuk file dengan izin eksekusi, ia tidak dapat menemukan perintah built-in. Gunakan `type cd` sebagai gantinya, yang akan melaporkan `cd is a shell builtin` dengan benar.
Bisakah `which` memberi tahu saya versi program mana yang terinstal?
Tidak. `which` hanya mengembalikan jalur. Untuk mendapatkan versi, pipe hasilnya: `$(which python3) –version` atau cukup `python3 –version`. Jalur dari `which` membantu Anda mengonfirmasi bahwa Anda menanyakan biner yang benar.
Mengapa `which python3` mengembalikan hasil yang berbeda ketika saya menggunakan `sudo`?
`sudo` mengeksekusi perintah dengan lingkungan root, termasuk `PATH` milik root, yang biasanya lebih ketat dari `PATH` pengguna biasa. Direktori seperti `~/.local/bin` atau jalur nvm/pyenv yang ditambahkan ke `.bashrc` pengguna tidak ada di `PATH` milik root. Selalu uji dengan `sudo which python3` secara terpisah saat men-debug eksekusi dengan hak istimewa yang ditingkatkan.
Apakah `which` tersedia di macOS?
Ya, macOS menyertakan `which` sebagai bagian dari userland turunan BSD-nya. Namun, versi macOS tidak mendukung flag `-a` di semua versi lama. Pada macOS modern dengan Homebrew, Anda mungkin memiliki GNU `which` yang terinstal bersama versi sistem. Gunakan `type -a which` di macOS untuk melihat implementasi mana yang aktif.
