Jadi, saya pikir saya memiliki pemahaman yang baik tentang ini, tetapi hanya menjalankan tes (dalam menanggapi percakapan di mana saya tidak setuju dengan seseorang) dan menemukan bahwa pemahaman saya cacat ...
Sedetail mungkin apa yang sebenarnya terjadi ketika saya menjalankan file di shell saya? Apa yang saya maksud adalah, jika saya mengetik: ./somefile some arguments
ke dalam shell saya dan tekan kembali (dan somefile
ada di cwd, dan saya telah membaca + mengeksekusi izin pada somefile
) lalu apa yang terjadi di bawah tenda?
Saya pikir jawabannya adalah:
- Shell melakukan syscall to
exec
, melewati path tosomefile
- Kernel memeriksa
somefile
dan melihat nomor ajaib file untuk menentukan apakah itu adalah format yang dapat ditangani prosesor - Jika angka ajaib menunjukkan bahwa file tersebut dalam format yang dapat dijalankan prosesor, maka
- proses baru dibuat (dengan entri dalam tabel proses)
somefile
dibaca / dipetakan ke memori. Tumpukan dibuat dan eksekusi melompat ke titik masuk kodesomefile
, denganARGV
diinisialisasi ke array parameter (achar**
,["some","arguments"]
)
- Jika angka ajaib adalah shebang maka
exec()
memunculkan proses baru seperti di atas, tetapi executable yang digunakan adalah interpreter yang dirujuk oleh shebang (misalnya/bin/bash
atau/bin/perl
) dansomefile
diteruskan keSTDIN
- Jika file tidak memiliki angka ajaib yang valid, maka kesalahan seperti "file tidak valid (angka sihir buruk): Kesalahan format Exec" terjadi
Namun seseorang mengatakan kepada saya bahwa jika file tersebut adalah teks biasa, maka shell mencoba mengeksekusi perintah (seolah-olah saya telah mengetik bash somefile
). Saya tidak percaya ini, tetapi saya hanya mencobanya, dan itu benar. Jadi saya jelas memiliki kesalahpahaman tentang apa yang sebenarnya terjadi di sini, dan ingin memahami mekanika.
Apa yang sebenarnya terjadi ketika saya menjalankan file di shell saya? (Dalam banyak detail masuk akal ...)
source somefile
sangat berbeda dari proses baru yang dipotong oleh./somefile
../somefile
akan menyebabkan bash untuk mengeksekusi perintahsomefile
jika file tidak memiliki angka ajaib. Saya pikir itu hanya akan menampilkan kesalahan, dan sebaliknya itu muncul secara efektifsource somefile
somefile
ini adalah file teks, maka shell baru akan muncul jika saya mencoba untuk mengeksekusinya. Fileecho $$
berperilaku berbeda jika saya mengeksekusi vs sumbernya.Jawaban:
Jawaban pasti untuk "bagaimana program dijalankan" di Linux adalah sepasang artikel di LWN.net berjudul, cukup mengejutkan, Bagaimana program dijalankan dan Bagaimana program dijalankan: ELF binari . Artikel pertama membahas skrip secara singkat. (Sebenarnya, jawaban pasti ada dalam kode sumber, tetapi artikel ini lebih mudah dibaca dan memberikan tautan ke kode sumber.)
Sebuah eksperimen kecil menunjukkan bahwa Anda sudah melakukannya dengan benar, dan bahwa eksekusi file yang berisi daftar perintah sederhana, tanpa shebang, perlu ditangani oleh shell. Halaman execve (2) berisi kode sumber untuk program pengujian, execve; kami akan menggunakannya untuk melihat apa yang terjadi tanpa shell. Pertama, tulis skrip test
testscr1
,, yang berisidan satu lagi
testscr2
, hanya berisiJadikan keduanya dapat dieksekusi, dan verifikasi bahwa keduanya berjalan dari shell:
Sekarang coba lagi, menggunakan
execve
(dengan asumsi Anda membuatnya di direktori saat ini):testscr1
masih berjalan, tetapitestscr2
menghasilkanIni menunjukkan bahwa shell menangani secara
testscr2
berbeda. Itu tidak memproses skrip itu sendiri, ia masih menggunakan/bin/sh
untuk melakukan itu; ini dapat diverifikasi dengan memipistestscr2
keless
:Di sistem saya, saya mengerti
Seperti yang Anda lihat, ada shell yang saya gunakan,
zsh
yang dimulailess
, dan shell kedua, polossh
(dash
di sistem saya), untuk menjalankan skrip, yang berjalanpstree
. Dalamzsh
hal ini ditangani olehzexecve
dalamSrc/exec.c
: shell digunakanexecve(2)
untuk mencoba menjalankan perintah, dan jika itu gagal, ia membaca file untuk melihat apakah ia memiliki shebang, memprosesnya sesuai (yang juga akan dilakukan oleh kernel), dan jika itu gagal mencoba menjalankan file dengansh
, asalkan tidak membaca nol byte dari file:bash
memiliki perilaku yang sama, diimplementasikanexecute_cmd.c
dengan komentar yang bermanfaat (seperti yang ditunjukkan oleh taliezin ):POSIX mendefinisikan satu set fungsi, yang dikenal sebagai yang
exec(3)
fungsi , yang membungkusexecve(2)
dan menyediakan fungsi ini juga; lihat jawaban muru untuk perinciannya. Di Linux setidaknya fungsi-fungsi ini diimplementasikan oleh pustaka C, bukan oleh kernel.sumber
Sebagian, ini tergantung pada
exec
fungsi keluarga tertentu yang digunakan.execve
, seperti yang diperlihatkan oleh Stephen Kitt secara terperinci, hanya menjalankan file dalam format biner yang benar atau skrip yang dimulai dengan shebang yang tepat.Namun ,
execlp
danexecvp
melangkah lebih jauh: jika shebang tidak benar, file dieksekusi dengan/bin/sh
di Linux. Dariman 3 exec
:Ini agak didukung oleh POSIX (penekanan milik saya):
Ini tidak menentukan bagaimana juru bahasa perintah diperoleh, jadi, tetapi tidak menentukan bahwa kesalahan harus diberikan. Saya kira, oleh karena itu, para pengembang Linux mengizinkan file-file tersebut untuk dijalankan
/bin/sh
(atau ini sudah menjadi praktik umum dan mereka hanya mengikuti sesuai).FWIW, manual FreeBSD untuk
exec(3)
juga menyebutkan perilaku serupa:AFAICT, bagaimanapun, tidak menggunakan shell umum
execlp
atauexecvp
secara langsung, mungkin untuk kontrol yang lebih baik terhadap lingkungan. Mereka semua menerapkan logika yang sama menggunakanexecve
.sumber
execl
,execlp
,execle
,execv
,execvp
danexecvpe
semua depan berakhir denganexecve
syscall; yang pertama disediakan oleh perpustakaan C, kernel hanya tahu tentangexecve
(danexecveat
saat ini).Ini bisa menjadi tambahan untuk jawaban Stephen Kitt, sebagai komentar dari
bash
sumber dalam fileexecute_cmd.c
:sumber
Itu dieksekusi sebagai skrip shell, itu tidak bersumber (misalnya, variabel yang diatur dalam file yang dieksekusi tidak mempengaruhi luar). Mungkin sisa-sisa dari masa lalu yang berkabut, ketika ada satu shell dan satu format yang dapat dieksekusi. Bukan yang dapat dieksekusi, itu harus berupa skrip shell.
sumber
exec()
atau kulitnya? Saya ingin lebih banyak internal