Learning Bash Book menyebutkan bahwa subkulit hanya akan mewarisi variabel lingkungan dan deskriptor file, dll., Dan itu tidak akan mewarisi variabel yang tidak diekspor:
$ var=15
$ (echo $var)
15
$ ./file # this file include the same command echo $var
$
Seperti yang saya tahu shell akan membuat dua subkulit untuk ()
dan untuk ./file
, tetapi mengapa dalam ()
kasus ini subkulit mengidentifikasi var
variabel meskipun tidak diekspor dan dalam ./file
kasus itu tidak mengidentifikasi itu?
# Strace for ()
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25617
# Strace for ./file
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25631
Saya mencoba menggunakan strace
untuk mencari tahu bagaimana ini terjadi dan mengejutkan saya menemukan bahwa bash akan menggunakan argumen yang sama untuk panggilan sistem klon, jadi ini berarti bahwa kedua proses bercabang di ()
dan ./file
harus memiliki ruang alamat proses proses yang sama dari induk, jadi mengapa dalam ()
kasus ini apakah variabel terlihat oleh subkulit dan hal yang sama tidak terjadi untuk ./file
kasus, meskipun argumen yang sama didasarkan pada panggilan sistem klon?
Jawaban:
Buku Bash Belajar salah. Subshell mewarisi semua variabel. Bahkan
$$
(PID dari shell asli) disimpan. Alasannya adalah bahwa untuk subkulit, shell hanya bercabang dan tidak mengeksekusi shell baru (sebaliknya, ketika Anda mengetik./file
, perintah baru dieksekusi, misalnya shell baru; pada output strace, lihat padaexecve
dan mirip) . Jadi, pada dasarnya, itu hanya salinan (dengan beberapa perbedaan yang terdokumentasi).Catatan: ini tidak khusus untuk bash; ini berlaku untuk shell apa pun.
sumber
-f
opsistrace
untuk melacak anak-anak juga? Itu perlu untuk menemukan eksekutif itu.Entah Anda atau buku ini membingungkan subkulit dengan subproses yang merupakan shell.
Beberapa konstruksi shell menghasilkan shell forking proses anak. Di Linux,
fork
adalah kasus khusus dariclone
pemanggilan sistem yang lebih umum , yang Anda amati dalamstrace
log. Anak itu menjalankan bagian dari skrip shell. Proses anak disebut subkulit . Konstruk semacam itu yang paling langsung adalahcommand1 &
:command1
dijalankan dalam subkulit, dan perintah selanjutnya dijalankan dalam shell induk. Konstruksi lain yang membuat subkulit meliputi substitusi perintah$(command2)
dan pipacommand3 | command4
(command3
berjalan dalam subkulit,command4
berjalan dalam subkulit di sebagian besar shell tetapi tidak dalam ksh atau zsh).Subkulit adalah salinan dari proses induk, sehingga tidak hanya memiliki variabel lingkungan yang sama, tetapi juga semua definisi internal yang sama: variabel (termasuk
$$
, ID proses dari proses shell asli), fungsi, alias, opsi, dll. Sebelum mengeksekusi kode dalam subkulit, bash menetapkan variabelBASHPID
ke ID proses proses anak.Ketika Anda menjalankan
./file
, ini menjalankan perintah eksternal. Pertama, shell membuat proses anak; maka proses anak ini mengeksekusi (denganexecve
panggilan sistem) file yang dapat dieksekusi./file
. Proses anak mewarisi atribut proses dari orang tuanya: lingkungan, direktori saat ini, dll. Aspek internal aplikasi hilang dalamexecve
panggilan: variabel yang tidak diekspor, fungsi, dll. Adalah gagasan bash yang tidak diketahui oleh kernel, dan mereka hilang ketika bash menjalankan program lain. Bahkan jika program lain itu adalah skrip bash, ia dijalankan oleh instance baru dari bash yang tidak tahu atau peduli bahwa proses induknya juga merupakan instance dari bash. Dengan demikian variabel shell (variabel yang tidak diekspor) tidak bertahanexecve
.sumber