Memahami perintah builtin shell

12

Di dalam manual bash , tertulis itu

Builtin commands are contained >>> within <<< the shell itself

Juga, jawaban ini menyatakan itu

A built-in command is simply a command that the shell carries out itself,
instead of interpreting it as a request to load and run some
>>> other program <<<

Ketika saya menjalankan compgen -bpada bash 4.4, saya menerima daftar semua shell builtin perintah. Saya melihat contohnya [dan killterdaftar sebagai builtin shell. Tapi lokasi sebenarnya adalah:

/usr/bin/[
/bin/kill

Saya berpikir bahwa menjadi builtinsarana bahwa perintah dikompilasi ke dalam /bin/bashexecutable. Jadi apa yang benar-benar membingungkan saya: Tolong perbaiki saya, tetapi bagaimana perintah yang terpisah bisa menjadi builtin, padahal sebenarnya itu bukan bagian dari shell?

perwujudan
sumber
1
Beberapa perintah awalnya ada sebagai utilitas terpisah. Kehadiran mereka sekarang adalah untuk kepatuhan standar POSIX, portabilitas, serta kompatibilitas ke belakang. Shell menerapkan beberapa fitur bawaan untuk kinerja. Mungkin ada alasan lain, tapi itu tentang hal itu tanpa terlalu banyak detail.
Sergiy Kolodyazhnyy
1
Alasan lain yang bisa saya pikirkan, adalah karena beberapa perintah bawaan diperlukan untuk shell secara khusus, seperti execmemanipulasi file deskriptor dan eval untuk mengevaluasi perintah. Mereka tidak diperlukan sebagai perintah mandiri
Sergiy Kolodyazhnyy

Jawaban:

16

Perintah-perintah yang dibangun ke dalam shell sering dibangun karena peningkatan kinerja yang memberi ini. Memanggil eksternal printf , misalnya, lebih lambat daripada menggunakan built-in printf.

Karena beberapa utilitas tidak perlu dibangun, kecuali mereka khusus, seperti cd, mereka juga disediakan sebagai utilitas eksternal . Ini adalah agar skrip tidak akan rusak jika mereka diinterpretasikan oleh shell yang tidak menyediakan built in yang setara.

Built-in beberapa shell juga menyediakan ekstensi untuk perintah setara eksternal. Bash printf, misalnya mampu melakukannya

$ printf -v message 'Hello %s' "world"
$ echo "$message"
Hello world

(cetak ke variabel) yang /usr/bin/printftidak bisa dilakukan eksternal karena tidak memiliki akses ke variabel shell di sesi shell saat ini (dan tidak dapat mengubahnya).

Utilitas bawaan juga tidak memiliki batasan bahwa baris perintah yang diperluas harus lebih pendek dari panjang tertentu. Perbuatan

printf '%s\n' *

Oleh karena itu aman jika printfperintah built-in shell. Pembatasan pada panjang baris perintah berasal dari fungsi execve()C library yang digunakan untuk mengeksekusi perintah eksternal. Jika baris perintah dan lingkungan saat ini lebih besar dari ARG_MAXbyte (lihat getconf ARG_MAXdi shell), panggilan ke execve()akan gagal. Jika utilitas dibangun ke dalam shell, execve()tidak harus dipanggil.

Utilitas bawaan lebih diutamakan daripada utilitas yang ditemukan di $PATH. Untuk menonaktifkan perintah bawaan bash, gunakan mis

enable -n printf

Ada daftar pendek utilitas yang perlu dibangun ke dalam shell (diambil dari daftar standar built-in khusus POSIX )

break
colon (:)
continue
dot (.)
eval
exec
exit
export
readonly
return
set
shift
times
trap
unset

Ini perlu dibangun karena mereka secara langsung memanipulasi lingkungan dan aliran program dari sesi shell saat ini. Utilitas eksternal tidak akan dapat melakukan itu.

Menariknya, cdbukan bagian dari daftar ini, tetapi POSIX mengatakan yang berikut tentang itu:

Karena cdmemengaruhi lingkungan eksekusi shell saat ini, selalu disediakan sebagai built-in shell biasa. Jika dipanggil dalam subkulit atau lingkungan eksekusi utilitas terpisah, seperti salah satu dari yang berikut:

(cd /tmp)
nohup cd
find . -exec cd {} \;

itu tidak mempengaruhi direktori kerja dari lingkungan pemanggil.

Karena itu saya berasumsi bahwa built-in "khusus" tidak dapat memiliki rekan eksternal, sedangkan cdsecara teori bisa saja (tetapi itu tidak akan berbuat banyak).

Kusalananda
sumber
IIRC, chdir/ cdadalah binari eksternal di dalam Unix / pra-Unix yang sangat awal sebelum forkdiperkenalkan.
Xophmeister
@Xophmeister Solaris 11.4 (beta) masih memiliki /usr/bin/cd, tetapi itu tidak akan benar-benar mengubah direktori kerja saat ini. Manualnya mengatakan: /usr/bin/cdtidak berpengaruh pada proses pemanggilan tetapi dapat digunakan untuk menentukan apakah direktori yang diberikan dapat ditetapkan sebagai direktori saat ini.
Kusalananda
2
Alasan lain yang agak spesifik untuk builtin: builtin killjuga bagus karena tidak perlu melakukan proses lain, bagus jika Anda telah mencapai batas jumlah proses Anda.
derobert
7

Anda (sangat dimengerti) bingung oleh kenyataan bahwa beberapa builtin ada baik sebagai builtin maupun sebagai perintah eksternal. Jadi, sementara Anda benar bahwa, misalnya, ada /bin/[perintah, itu tidak berarti bahwa "lokasi sebenarnya" ada di /bin.

Cara mudah apa pun untuk menguji ini adalah menjalankannya typedengan -asakelar yang akan menampilkan semua instance perintah yang tersedia. Di sistem Arch saya, itu menunjukkan:

$ type -a [
[ is a shell builtin
[ is /sbin/[
[ is /usr/sbin/[
[ is /usr/bin/[

Perhatikan itu /sbin, /usr/sbindan /binsemua symlink mengarah ke /usr/bin, jadi hanya ada satu eksternal [:

$ readlink -f /usr/sbin /sbin /bin/
/usr/bin
/usr/bin
/usr/bin

Seperti yang Anda lihat, [keduanya adalah builtin dan perintah eksternal, dan hal yang sama berlaku untuk berbagai builtin shell lainnya. Namun, itu tidak mengubah fakta bahwa mereka juga shell builtin, dikompilasi ke dalam shell itu sendiri.

terdon
sumber
mengapa distro. menyediakan perintah eksternal yang terpisah untuk perintah internal yang sudah ada? mengapa mereka menduplikasi?
LoveWithMaths
1
@linuxuser beberapa utilitas ini diperlukan oleh POSIX, dan Anda tidak bisa tahu apakah shell yang kebetulan digunakan pengguna juga akan menyediakan builtin. Jangan menganggapnya sebagai perintah internal OS, itu hanya perintah internal shell, dan shell dapat berubah.
terdon
Saya ragu sekarang, apakah perintah internal disediakan oleh shell; lalu siapa yang memberikan perintah eksternal? seperti saya telah mengamati banyak perintah yang tersedia sebagai perintah internal maupun eksternal, tetapi saya tidak menginstalnya secara eksplisit; jadi siapa yang memberikan perintah eksternal? Distro menyediakannya dengan benar?
LoveWithMaths
@linuxuser tergantung pada perintah dan sistem operasi. Misalnya, di Arch Linux saya, /bin/printfdiinstal oleh coreutilspaket dan /bin/killoleh util-linux.
terdon
Saya minta maaf tapi saya masih belum jelas, yang mana di atas disediakan oleh distro? dan bagaimana dengan yang lain yang tidak disediakan oleh distro lalu siapa yang menyediakannya.
LoveWithMaths