Ada perbedaan kuat antara builtin dan kata kunci, dalam cara Bash mem-parsing kode Anda. Sebelum kita berbicara tentang perbedaannya, mari kita daftarkan semua kata kunci dan bawaan:
Builtin:
$ compgen -b
. : [ alias bg bind break
builtin caller cd command compgen complete compopt
continue declare dirs disown echo enable eval
exec exit export false fc fg getopts
hash help history jobs kill let local
logout mapfile popd printf pushd pwd read
readarray readonly return set shift shopt source
suspend test times trap true type typeset
ulimit umask unalias unset wait
Kata kunci:
$ compgen -k
if then else elif fi case
esac for select while until do
done in function time { }
! [[ ]] coproc
Perhatikan bahwa, misalnya [
adalah builtin dan itu [[
adalah kata kunci. Saya akan menggunakan keduanya untuk menggambarkan perbedaan di bawah ini, karena mereka adalah operator terkenal: semua orang tahu mereka dan menggunakannya secara teratur (atau harus).
Kata kunci dipindai dan dipahami oleh Bash sangat awal dalam penguraiannya. Ini memungkinkan misalnya sebagai berikut:
string_with_spaces='some spaces here'
if [[ -n $string_with_spaces ]]; then
echo "The string is non-empty"
fi
Ini berfungsi dengan baik, dan Bash akan dengan senang hati mengeluarkan
The string is non-empty
Perhatikan bahwa saya tidak mengutip $string_with_spaces
. Sedangkan yang berikut ini:
string_with_spaces='some spaces here'
if [ -n $string_with_spaces ]; then
echo "The string is non-empty"
fi
menunjukkan bahwa Bash tidak bahagia:
bash: [: too many arguments
Mengapa ini bekerja dengan kata kunci dan tidak dengan builtin? karena ketika Bash mem-parsing kode itu, ia melihat [[
mana yang merupakan kata kunci, dan memahami sangat awal bahwa itu istimewa. Jadi akan mencari penutup ]]
dan akan memperlakukan bagian dalam dengan cara yang khusus. Builtin (atau perintah) diperlakukan sebagai perintah aktual yang akan dipanggil dengan argumen. Dalam contoh terakhir ini, bash memahami bahwa ia harus menjalankan perintah [
dengan argumen (ditampilkan satu per baris):
-n
some
spaces
here
]
sejak ekspansi variabel, penghapusan kutipan, ekspansi pathname dan pemisahan kata terjadi. Perintah itu [
ternyata dibangun di shell, jadi dieksekusi dengan argumen ini, yang menghasilkan kesalahan, karenanya keluhan.
Dalam praktiknya, Anda melihat bahwa perbedaan ini memungkinkan perilaku canggih, yang tidak mungkin dilakukan dengan builtin (atau perintah).
Masih dalam praktiknya, bagaimana Anda bisa membedakan builtin dari kata kunci? ini adalah eksperimen yang menyenangkan untuk dilakukan:
$ a='['
$ $a -d . ]
$ echo $?
0
Ketika Bash mem-parsing baris $a -d . ]
, ia melihat tidak ada yang istimewa (yaitu, tidak ada alias, tidak ada pengalihan, tidak ada kata kunci), jadi itu hanya melakukan ekspansi variabel. Setelah ekspansi variabel, terlihat:
[ -d . ]
jadi jalankan perintah (builtin) [
dengan argumen -d
, .
dan ]
, yang, tentu saja benar (ini hanya menguji apakah .
sebuah direktori).
Sekarang lihat:
$ a='[['
$ $a -d . ]]
bash: [[: command not found
Oh Itu karena ketika Bash melihat baris ini, ia melihat tidak ada yang istimewa, dan karenanya memperluas semua variabel, dan akhirnya melihat:
[[ -d . ]]
Saat ini, pemanjangan alias dan pemindaian kata kunci telah lama dilakukan dan tidak akan dilakukan lagi, jadi Bash mencoba menemukan perintah yang dipanggil [[
, tidak menemukannya, dan mengeluh.
Sepanjang garis yang sama:
$ '[' -d . ]
$ echo $?
0
$ '[[' -d . ]]
bash: [[: command not found
dan
$ \[ -d . ]
$ echo $?
0
$ \[[ -d . ]]
bash: [[: command not found
Ekspansi alias juga sesuatu yang agak istimewa. Anda semua telah melakukan yang berikut setidaknya sekali:
$ alias ll='ls -l'
$ ll
.... <list of files in long format> ....
$ \ll
bash: ll: command not found
$ 'll'
bash: ll: command not found
Alasannya sama: ekspansi alias terjadi jauh sebelum ekspansi variabel dan penghapusan kutipan.
Kata kunci vs Alias
Sekarang menurut Anda apa yang terjadi jika kami menetapkan alias untuk menjadi kata kunci?
$ alias mytest='[['
$ mytest -d . ]]
$ echo $?
0
Oh, berhasil! jadi alias bisa digunakan untuk kata kunci alias! bagus untuk mengetahui.
Kesimpulan: builtin benar-benar berperilaku seperti perintah: mereka berhubungan dengan tindakan yang dieksekusi dengan argumen yang mengalami ekspansi variabel langsung dan pemisahan kata dan globbing. Ini benar-benar seperti memiliki perintah eksternal di suatu tempat di /bin
atau /usr/bin
yang disebut dengan argumen yang diberikan setelah ekspansi variabel, dll. Perhatikan bahwa ketika saya mengatakan itu benar-benar seperti memiliki perintah eksternal yang saya maksud dengan hanya berkenaan dengan argumen, pemisahan kata, penggumpalan, ekspansi variabel, dll. builtin dapat memodifikasi keadaan internal shell!
Kata kunci, di sisi lain, dipindai dan dipahami sangat awal, dan memungkinkan untuk perilaku shell canggih: shell akan dapat melarang pemisahan kata atau perluasan pathname, dll.
Sekarang lihat daftar bawaan dan kata kunci dan coba cari tahu mengapa beberapa perlu kata kunci.
!
adalah kata kunci. Tampaknya mungkin untuk meniru perilakunya dengan suatu fungsi:
not() {
if "$@"; then
return false
else
return true
fi
}
tapi ini akan melarang konstruksi seperti:
$ ! ! true
$ echo $?
0
atau
$ ! { true; }
echo $?
1
Sama untuk time
: lebih kuat untuk memiliki kata kunci sehingga dapat mengatur waktu perintah kompleks dan saluran pipa dengan pengalihan:
$ time grep '^#' ~/.bashrc | { i=0; while read -r; do printf '%4d %s\n' "$((++i))" "$REPLY"; done; } > bashrc_numbered 2>/dev/null
Jika di time
mana hanya perintah (bahkan builtin), itu hanya akan melihat argumen grep
, ^#
dan /home/gniourf/.bashrc
, waktu ini, dan kemudian hasilnya akan melewati bagian-bagian yang tersisa dari pipa. Tetapi dengan kata kunci, Bash dapat menangani semuanya! itu bisa time
menyelesaikan pipa, termasuk pengalihan! Jika time
hanya perintah, kami tidak bisa melakukan:
$ time { printf 'hello '; echo world; }
Cobalah:
$ \time { printf 'hello '; echo world; }
bash: syntax error near unexpected token `}'
Coba perbaiki (?):
$ \time { printf 'hello '; echo world;
time: cannot run {: No such file or directory
Putus asa.
Kata kunci vs alias?
$ alias mytime=time
$ alias myls=ls
$ mytime myls
Menurut Anda apa yang terjadi?
Sungguh, builtin seperti sebuah perintah, kecuali itu dibangun di shell, sedangkan kata kunci adalah sesuatu yang memungkinkan untuk perilaku canggih! kita dapat mengatakan itu bagian dari tata bahasa shell.