Perintah command Bash: melewati fungsi dan memeriksa perintah

command adalah perintah bawaan shell yang melewatkan pencarian fungsi shell dan menjalankan perintah bawaan atau perintah eksternal yang ditemukan di PATH. Ini terutama digunakan untuk memanggil perintah asli ketika fungsi pembungkus dengan nama yang sama dibuat, atau untuk memeriksa dengan command -v apakah shell saat ini dapat menemukan perintah tersebut.

Shell adalah penafsir perintah, sedangkan PATH berisi daftar direktori pencarian. Di Bash, -v dan -V memeriksa bagaimana nama dikenali; -p menggunakan jalur pencarian standar. Kegunaan ini berbeda dari exec, env, dan builtin.

Apa itu perintah command?

Sebuah fungsi shell dapat memiliki nama yang sama dengan perintah eksternal. Dalam hal ini, memanggil nama secara langsung di dalam fungsi dapat membuatnya memanggil dirinya sendiri lagi, menyebabkan rekursi. Memberi prefiks dengan command melewati fungsi shell dengan nama yang sama dan memilih perintah bawaan Bash atau executable yang ditemukan di PATH.

command adalah perintah bawaan Bash dan beberapa shell lainnya. Utilitas ini juga didefinisikan dalam POSIX, tetapi keluaran rinci dan perilaku tambahan dapat berbeda menurut shell.

Sintaks Dasar

command [-pVv] nama [argumen ...]

Ini adalah skema sintaks; tanda kurung siku dan titik-titik menandakan bagian opsional, bukan teks yang harus disalin. Tanpa -v atau -V, command menjalankan nama yang ditentukan.

command ls -la
command printf '%s\n' 'hello'

Dalam sebagian besar situasi, tampaknya seperti perintah dijalankan secara langsung. Perbedaannya menjadi jelas ketika ada fungsi shell dengan nama yang sama.

Memanggil perintah asli di dalam fungsi shell

Simpan contoh ini sebagai daftar.sh dan jalankan bash daftar.sh -la. Contoh memerlukan Bash dan GNU ls karena memakai --color=auto. Fungsi mencetak pesan lalu meneruskan argumen ke ls; fungsi hanya ada dalam proses skrip ini.

#!/usr/bin/env bash
ls() {
  printf '%s\n' 'Menampilkan daftar.'
  command ls --color=auto "$@"
}

ls "$@"

Menulis ls "$@" di dalam fungsi akan memanggil fungsi yang sama lagi. command ls melewati pencarian fungsi, sehingga sebuah perintah bawaan Bash atau ls eksternal di PATH akan dijalankan.

"$@" mempertahankan batas setiap argumen. Misalnya, bash daftar.sh -d -- "folder dengan spasi" memperlakukan nama folder yang ada sebagai satu argumen. $* atau $@ tanpa tanda kutip dapat memecah spasi dan memperluas karakter wildcard. Status ls menjadi status akhir fungsi dan skrip.

Memeriksa apakah sebuah perintah ada menggunakan command -v

-v menghasilkan bentuk ringkas tentang bagaimana nama yang ditentukan ditafsirkan di shell saat ini. Ini mengembalikan status sukses jika perintah ditemukan dan status gagal jika tidak, sehingga berguna untuk memeriksa keberadaan dalam skrip.

command -v git
command -v cd
command -v printf

Output dapat menggambarkan tidak hanya jalur eksekusi tetapi juga perintah bawaan, fungsi, atau alias. Oleh karena itu, hasilnya tidak boleh selalu dianggap sebagai jalur file dalam semua kasus.

if command -v curl >/dev/null 2>&1; then
 printf '%s\n' 'curl dikenali oleh shell.'
else
 printf '%s\n' 'curl tidak ditemukan.' >&2
fi

Periksa informasi rinci dengan perintah -V

-V mencetak deskripsi rinci yang lebih mudah dibaca manusia dibandingkan -v.

command -V ls
command -V cd
command -V deploy

Dalam otomatisasi, jangan mengurai kalimat keluaran -V karena formatnya bergantung pada shell dan lokal. Gunakan status keluar command -v untuk memeriksa apakah nama dikenali. Fungsi yang dikenali dalam pemeriksaan itu tetap dilewati oleh command nama saat eksekusi.

command -p dan jalur pencarian default

-p menggunakan nilai PATH default yang disediakan oleh shell untuk mencari utilitas standar. Ini dapat digunakan ketika PATH yang dimodifikasi pengguna tidak dapat diandalkan atau ketika Anda perlu menemukan perintah standar.

command -p getconf PATH
command -p ls

Nilai sebenarnya dari path default bervariasi tergantung sistem. -p tidak menjamin path absolut tertentu atau program dari penyedia tertentu, jadi dalam skrip di mana keamanan penting, Anda harus merancang lingkungan eksekusi dan batas kepercayaan secara terpisah.

Ringkasan opsi perintah

Opsi Deskripsi
-v Menampilkan interpretasi shell saat ini secara ringkas tanpa mengeksekusi perintah.
-V Mencetak penjelasan rinci tentang bagaimana perintah diinterpretasikan.
-p Menjalankan perintah menggunakan jalur pencarian default di mana utilitas standar dapat ditemukan.

Peringatan saat melewati alias

Alias diperluas saat shell membaca perintah, sebelum eksekusi. Biasanya command ls tidak memperluas alias ls dan melewati fungsi dengan nama yang sama. Namun, command sendiri dapat didefinisikan sebagai alias atau fungsi; dalam Bash, alias yang berakhir dengan spasi juga dapat menyebabkan kata berikutnya diperiksa untuk perluasan alias.

Semua kandidat untuk nama saat ini dapat diperiksa terlebih dahulu dengan type -a di Bash.

type -a ls
command -V ls

Garis miring terbalik pada \ls mencegah perluasan alias tersebut, tetapi tidak melewati fungsi ls. Jalur absolut menghindari pencarian berdasarkan nama.

\ls
/usr/bin/ls

Jalur absolut dapat berbeda menurut sistem; periksa dengan type -P ls sebelum menggunakan /usr/bin/ls. Kedua bentuk ini tetap memerlukan pengutipan argumen yang tepat.

Perbandingan perintah, builtin, exec, env

Perintah Peran Utama
command name Melewati pencarian fungsi shell dengan nama yang sama dan mengeksekusi perintah built-in atau perintah PATH.
builtin name Secara eksplisit mengeksekusi perintah Bash built-in dengan nama yang sama.
exec name Mengganti proses shell saat ini dengan program baru. Jika berhasil, tidak akan kembali ke shell asli.
env VAR=value name Menjalankan perintah eksternal dalam lingkungan dengan variabel lingkungan yang disesuaikan.
type name Menunjukkan bagaimana Bash saat ini menafsirkan nama tanpa mengeksekusi perintah.

Jika ingin memastikan perintah bawaan Bash dipanggil dari dalam fungsi dengan nama yang sama, gunakan builtin. Gunakan command jika perintah bawaan maupun program eksternal boleh dijalankan, tetapi fungsi shell dengan nama itu harus dilewati.

Prinsip penggunaan command -v dalam skrip

Membuang keluaran dan memeriksa status keluar

Simpan contoh sebagai cek-rsync.sh, lalu jalankan bash cek-rsync.sh. Jika nama tidak dikenali, skrip menampilkan pesan dan keluar dengan status 1. Jika dikenali, skrip menampilkan konfirmasi dan keluar dengan status 0; contoh ini tidak menjalankan sinkronisasi.

#!/usr/bin/env bash
if ! command -v rsync >/dev/null 2>&1; then
  printf '%s\n' 'rsync diperlukan.' >&2
  exit 1
fi
printf '%s\n' 'rsync dikenali oleh shell.'

Metode ini tidak bergantung pada format keluaran. Untuk menyembunyikan bahkan pesan kesalahan, baik keluaran standar maupun kesalahan standar harus dialihkan.

Pemeriksaan tambahan jika diperlukan file eksekusi biasa

command -v juga dapat menemukan alias, fungsi, atau perintah bawaan. Dalam Bash, periksa terlebih dahulu bahwa type -t menghasilkan file, lalu periksa jalur yang dikembalikan. Ini menghindari kesalahan ketika nama fungsi atau perintah bawaan kebetulan sama dengan nama file lokal.

Simpan contoh sebagai cek-file.sh. Jalankan bash cek-file.sh ls untuk memeriksa ls eksternal, atau bash cek-file.sh cd untuk melihat penolakan perintah bawaan. Contoh ini memeriksa shell Bash yang menjalankan skrip, bukan definisi lokal yang tidak diwariskan dari terminal.

#!/usr/bin/env bash
if [ "$#" -ne 1 ]; then
  printf '%s\n' 'Penggunaan: bash cek-file.sh nama' >&2
  exit 1
fi
[ "$(type -t -- "$1")" = file ] || exit 1
path=$(command -v -- "$1") || exit 1

if [ -f "$path" ] && [ -x "$path" ]; then
  printf 'File yang dapat dijalankan: %s\n' "$path"
else
  printf '%s\n' 'Bukan file biasa yang dapat dijalankan.' >&2
  exit 1
fi

Karena jalur relatif atau keluaran shell khusus mungkin dikembalikan, rancang kondisi sesuai dengan tujuan yang dimaksud.

Memahami masalah TOCTOU

TOCTOU (time of check to time of use) adalah selang antara pemeriksaan dan penggunaan hasilnya.

Jika Anda memeriksa keberadaan sebuah perintah dan kemudian mengeksekusinya nanti, PATH atau file dapat berubah di antara waktu tersebut. Ini cukup untuk panduan pengguna sederhana, tetapi di lingkungan yang sensitif terhadap keamanan, jangan hanya percaya pada hasil pemeriksaan saja dan gunakan jalur serta izin yang terkendali.

Status keluar

Dalam mode eksekusi Bash, perintah yang tidak ditemukan menghasilkan status 127; perintah yang ditemukan tetapi tidak dapat dijalankan menghasilkan 126. Jika dijalankan, statusnya adalah status perintah tersebut. -v dan -V berhasil jika nama ditemukan dan gagal jika tidak.

command false
printf 'status=%d\n' "$?"

command does-not-exist
printf 'status=%d\n' "$?"

Contoh pertama menampilkan status=1, sedangkan nama yang tidak ada biasanya menghasilkan diagnostik dan status=127, selama tidak ada definisi lokal atau penangan khusus untuk nama itu. Setiap printf membaca status baris sebelumnya lalu mengembalikan statusnya sendiri; blok ini tidak mempertahankan 127 sebagai status akhir.

Pertanyaan yang Sering Diajukan

Apakah command hanya menjalankan perintah eksternal?

Tidak. Dalam Bash, ia melewati fungsi shell dan kemudian menjalankan perintah bawaan atau perintah eksternal yang ditemukan di PATH. Untuk menemukan hanya file eksternal, Anda perlu memeriksa jalur menggunakan alat seperti type -P.

Apakah hasil dari command -v selalu berupa path absolut?

Tidak. Hasil bisa berasal dari alias, fungsi, kata yang dicadangkan, perintah bawaan, atau file yang dapat dieksekusi. Gunakan status keluar untuk memeriksa keberadaan perintah.

Apakah bisa digunakan dalam bentuk sudo command...?

Karena command adalah built-in shell, sudo mungkin tidak dapat mengeksekusinya secara langsung seperti program eksekusi terpisah. Biasanya, Anda langsung meneruskan perintah eksternal yang diperlukan ke sudo, atau jika sintaks shell diperlukan, Anda harus secara eksplisit menjalankan shell sambil memahami kutipan dan implikasi keamanannya.

Mengapa command -v lebih baik daripada which?

command -v disediakan oleh shell dan mencerminkan interpretasi perintah dari shell saat ini. which sering kali merupakan program eksternal, dan tergantung pada implementasinya, mungkin tidak menangani alias atau fungsi dengan benar.

Bagaimana saya bisa mengabaikan fungsi dan hanya mengeksekusi perintah built-in?

Di Bash, gunakan builtin name. command name dapat mengeksekusi tidak hanya perintah bawaan tetapi juga perintah eksternal di PATH.

Apakah opsi yang sama dapat digunakan di shell lain?

Operasi inti dari -p, -v, dan -V didefinisikan dalam POSIX, tetapi pesan keluaran dan fitur tambahan dapat bervariasi menurut shell. Untuk otomatisasi, tentukan shell target dan periksa dokumentasinya.

Ringkasan

command berguna untuk memanggil perintah asli yang mungkin tersembunyi oleh fungsi shell dan memeriksa apakah perintah tersebut dapat ditemukan di shell saat ini. Gunakan command name untuk mengeksekusi, command -v name untuk memeriksa keberadaan, dan command -V name untuk deskripsi detail yang mudah dibaca manusia.

Saat memeriksa semua kandidat dan jenis perintah, gunakan type -a secara bersamaan. Perintah dasar lainnya dibahas dalam referensi perintah Linux.

Lihat dokumen resmi