Menurut ini dan ini , subkulit dimulai dengan menggunakan tanda kurung (…)
.
( echo "Hello" )
Menurut ini , ini dan ini , suatu proses bercabang ketika perintah dimulai dengan a&
echo "Hello" &
Spesifikasi Posix menggunakan kata subshell
di halaman ini tetapi tidak mendefinisikannya dan, juga, pada halaman yang sama, tidak mendefinisikan "proses anak" .
Keduanya menggunakan fork()
fungsi kernel , benar?
Apa perbedaan pastinya untuk menyebut beberapa garpu sebagai "sub-shell" dan beberapa garpu lainnya sebagai "proses anak".
child process
dapat memiliki lingkungan yang berbeda darimain
: Seperti di( LANG=C eval 'echo "$LANG"' )
. Apakah proses anak itu (di dalam kurung) juga merupakan subkulit (lingkungan yang berbeda)?( )
adalah dengan definisi subkulit dengan lingkungan eksekusi sendiri. Maksud saya adalah bahwa subkulit tidak perlu diimplementasikan sebagai proses anak (seperti yang ditunjukkan Stéphane dalam jawabannya dengan contoh ksh93). Sepertinya subkulit dan proses anak belum menjadi baik hasil darifork()
panggilan; jadi, mencari perbedaan antara dua jenis garpu sepertinya bukan sudut pandang yang tepat bagi saya. Itu sebabnya saya mencoba untuk lebih memahami pertanyaan Anda.Jawaban:
Dalam terminologi POSIX, lingkungan subkulit terkait dengan gagasan Lingkungan Eksekusi Shell .
Lingkungan subkulit adalah lingkungan eksekusi shell terpisah yang dibuat sebagai duplikat dari lingkungan induk. Lingkungan eksekusi itu mencakup hal-hal seperti file yang dibuka, umask, direktori kerja, variabel shell / fungsi / alias ...
Perubahan pada lingkungan subkulit itu tidak memengaruhi lingkungan induk.
Secara tradisional di shell Bourne atau ksh88 yang menjadi dasar spesifikasi POSIX, yang dilakukan dengan forking proses anak.
Area-area di mana POSIX membutuhkan atau mengizinkan perintah untuk dijalankan dalam lingkungan subshell adalah area-area di mana secara tradisional ksh88 memotong proses shell anak.
Namun itu tidak memaksa implementasi untuk menggunakan proses anak untuk itu.
Shell dapat memilih untuk mengimplementasikan lingkungan eksekusi yang terpisah dengan cara apa pun yang mereka suka.
Sebagai contoh, ksh93 melakukannya dengan menyimpan atribut dari lingkungan eksekusi induk dan mengembalikannya setelah penghentian lingkungan subkulit dalam konteks di mana forking dapat dihindari (sebagai optimasi karena forking cukup mahal pada kebanyakan sistem).
Misalnya, di:
POSIX memang mengharuskan
cd /foo
untuk berjalan di lingkungan yang terpisah dan itu untuk menampilkan sesuatu seperti:Itu tidak mengharuskannya untuk dijalankan dalam proses terpisah. Sebagai contoh, jika stdout menjadi pipa yang rusak,
pwd
jalankan di lingkungan subshell bisa saja SIGPIPE dikirim ke satu-satunya proses shell.Sebagian besar shell termasuk
bash
akan mengimplementasikannya dengan mengevaluasi kode di(...)
dalam proses anak (sementara proses induk menunggu penghentiannya), tetapi ksh93 sebaliknya akan menjalankan kode di dalam(...)
, semua dalam proses yang sama:cd
, simpan direktori kerja sebelumnya (biasanya pada deskriptor file dibuka dengan O_CLOEXEC), simpan nilai OLDPWD, variabel PWD dan apa pun yangcd
mungkin memodifikasi dan kemudian lakukanchdir("/bar")
fchdir()
pada yang disimpan fd), dan segala sesuatu yang subkulit mungkin telah dimodifikasi.Ada konteks di mana proses anak tidak dapat dihindari. ksh93 tidak bercabang di:
var=$(subshell)
(subshell)
Tetapi apakah dalam
{ subshell; } &
{ subshell; } | other command
Artinya, kasus-kasus di mana hal-hal harus berjalan dalam proses terpisah sehingga mereka dapat berjalan secara bersamaan.
optimisasi ksh93 melangkah lebih jauh dari itu. Misalnya, saat dalam
kebanyakan shell akan melakukan proses, meminta anak menjalankan
pwd
perintah dengan stdout diarahkan ke pipa,pwd
menulis direktori kerja saat ini ke pipa itu, dan proses induk membaca hasilnya di ujung lain pipa,ksh93
virtualisasi semua itu dengan tidak membutuhkan garpu atau pipa. Garpu dan pipa hanya akan digunakan untuk perintah non-builtin.Perhatikan bahwa ada konteks lain yang mensub kulit shell proses anak. Misalnya, untuk menjalankan perintah yang disimpan dalam executable yang terpisah (dan itu bukan skrip yang dimaksudkan untuk penerjemah shell yang sama), sebuah shell harus melakukan proses untuk menjalankan perintah itu di dalamnya karena jika tidak maka tidak akan dapat menjalankan lebih banyak perintah setelah perintah itu kembali.
Di:
Itu bukan subkulit, perintah akan dievaluasi dalam lingkungan eksekusi shell saat ini,
n
variabel lingkungan eksekusi shell saat ini akan bertambah, tetapi shell akan memotong proses anak untuk mengeksekusi/bin/echo
perintah itu di dalamnya dengan perluasan$((n += 1))
sebagai argumen .Banyak shell mengimplementasikan optimasi karena mereka tidak melakukan proses anak untuk menjalankan perintah eksternal jika itu perintah terakhir dari skrip atau subkulit (untuk subkulit yang diimplementasikan sebagai proses anak). (
bash
Namun hanya melakukannya jika perintah itu adalah satu-satunya perintah dari subkulit).Apa artinya itu adalah, dengan cangkang tersebut, jika perintah terakhir dalam subkulit adalah perintah eksternal, subkulit tersebut tidak menyebabkan proses tambahan untuk dimunculkan. Jika Anda membandingkan:
dengan
akan ada jumlah proses yang sama dibuat, hanya dalam kasus kedua, garpu kedua dilakukan sebelumnya sehingga
a=2
dijalankan di lingkungan subkulit.sumber
Subkulit
Cangkang anak juga disebut subkulit. Subshell dapat dibuat dari shell induk dan dari shell lain. Subshell dapat dibuat menggunakan:
1. Daftar Proses
Daftar proses adalah pengelompokan perintah terlampir dalam tanda kurung. Contoh:
Ini akan mencetak direktori kerja saat ini dan jumlah shell yang dihasilkan. Perhatikan Memanggil subkulit itu mahal.
2. Proses ulang
Ini memunculkan subkulit dalam mode latar belakang dan menjalankan perintah di dalam subkulit itu.
Jika Anda mengetik
jobs
perintahAnda akan melihat tidur sebagai proses latar belakang berjalan di latar belakang.
Forking Proses Anak
Proses anak dalam komputasi adalah proses yang dibuat oleh proses lain. Setiap kali perintah eksternal dijalankan, proses anak dibuat. Tindakan ini disebut forking.
Seperti
ps -f
perintah eksternal (mis. Perintah eksternal, kadang-kadang disebut perintah filesystem, adalah program yang ada di luar bash shell.) Ini akan membuat proses anak dengan id induk dari bash shell dari mana ia dieksekusi.sumber
Keduanya (kulit anak dan kulit anak) adalah proses terpisah dari kulit induk (keduanya kulit anak-anak kulit induk). Artinya, mereka memiliki PID yang berbeda. Dan keduanya dimulai dengan garpu (copy) dari shell induk.
Subshell adalah salinan dari shell induk di mana variabel, fungsi, bendera dan semuanya tersedia seperti di shell induk. Modifikasi nilai-nilai tersebut tidak mempengaruhi induk.
Shell anak dimulai sebagai garpu tetapi akan diset ulang ke nilai default shell yang diberikan oleh konfigurasi awal. Itu menjadi proses yang digunakan untuk mengeksekusi beberapa kode (baik shell atau perintah).
Subkulit dapat mengakses nilai variabel:
Shell anak tidak dapat (variabel yang tidak diekspor):
sumber