Apa perbedaan yang tepat antara "subkulit" dan "proses anak"?

16

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 subshelldi 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".

NotAnUnixNazi
sumber
Tidak jelas mengapa Anda menautkan POSIX Rationale: Base Definition dan bukannya Base Definition sendiri: 3.93 Child Process " Proses baru yang dibuat (oleh fork (), posix_spawn (), atau ...) dengan proses yang diberikan" ; 3.376 Subshell "Lingkungan eksekusi shell, dibedakan dari lingkungan eksekusi shell utama atau saat ini" . Jadi, bukan contoh hal yang sama. Apakah ini perbedaan yang Anda cari?
fra-san
@ fra-san A child processdapat memiliki lingkungan yang berbeda dari main: Seperti di ( LANG=C eval 'echo "$LANG"' ). Apakah proses anak itu (di dalam kurung) juga merupakan subkulit (lingkungan yang berbeda)?
NotAnUnixNazi
Ekspresi di ( )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 dari fork()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.
fra-san
Ah, sekarang saya melihat bahwa halaman tldp yang Anda tautkan sebenarnya mengatakan bahwa subkulit adalah proses anak. Menurut pendapat saya definisi itu mungkin merupakan penyederhanaan yang menyesatkan.
fra-san

Jawaban:

15

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:

cd /foo; pwd
(cd /bar; pwd)
pwd

POSIX memang mengharuskan cd /foountuk berjalan di lingkungan yang terpisah dan itu untuk menampilkan sesuatu seperti:

/foo
/bar
/foo

Itu tidak mengharuskannya untuk dijalankan dalam proses terpisah. Sebagai contoh, jika stdout menjadi pipa yang rusak, pwdjalankan di lingkungan subshell bisa saja SIGPIPE dikirim ke satu-satunya proses shell.

Sebagian besar shell termasuk bashakan 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:

  • ingat itu dalam lingkungan subkulit.
  • setelah itu cd, simpan direktori kerja sebelumnya (biasanya pada deskriptor file dibuka dengan O_CLOEXEC), simpan nilai OLDPWD, variabel PWD dan apa pun yang cdmungkin memodifikasi dan kemudian lakukanchdir("/bar")
  • sekembalinya dari subkulit, direktori kerja saat ini dipulihkan (dengan 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

var=$(pwd)

kebanyakan shell akan melakukan proses, meminta anak menjalankan pwdperintah dengan stdout diarahkan ke pipa, pwdmenulis direktori kerja saat ini ke pipa itu, dan proses induk membaca hasilnya di ujung lain pipa, ksh93virtualisasi 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:

/bin/echo "$((n += 1))"

Itu bukan subkulit, perintah akan dievaluasi dalam lingkungan eksekusi shell saat ini, nvariabel lingkungan eksekusi shell saat ini akan bertambah, tetapi shell akan memotong proses anak untuk mengeksekusi /bin/echoperintah 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). ( bashNamun 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:

a=1; /bin/echo "$a"; a=2; /bin/echo "$a"

dengan

a=1; /bin/echo "$a"; (a=2; /bin/echo "$a")

akan ada jumlah proses yang sama dibuat, hanya dalam kasus kedua, garpu kedua dilakukan sebelumnya sehingga a=2dijalankan di lingkungan subkulit.

Stéphane Chazelas
sumber
1

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:

( pwd ; (echo $BASH_SUBSHELL)) 

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.

coproc sleep 10

Jika Anda mengetik jobsperintah

[1]+  Running                 coproc COPROC sleep 10 &

Anda 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.

$ps -f
UID        PID  PPID  C STIME TTY          TIME CMD  
umcr7     3647  3638  0 13:54 pts/0    00:00:00 bash
umcr7     3749  3647  0 13:59 pts/0    00:00:00 ps -f

Seperti ps -fperintah 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.

Muhammad Umar Amanat
sumber
0

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:

$ x=123; ( echo "$x")
123

Shell anak tidak dapat (variabel yang tidak diekspor):

$ x=234; sh -c 'echo "x=$x"'
x=
NotAnUnixNazi
sumber