Jika Anda menggunakan strace
Anda dapat melihat bagaimana skrip shell dijalankan saat dijalankan.
Contoh
Katakanlah saya memiliki skrip shell ini.
$ cat hello_ul.bash
#!/bin/bash
echo "Hello Unix & Linux!"
Menjalankannya menggunakan strace
:
$ strace -s 2000 -o strace.log ./hello_ul.bash
Hello Unix & Linux!
$
Lihat di dalam strace.log
file mengungkapkan hal berikut.
...
open("./hello_ul.bash", O_RDONLY) = 3
ioctl(3, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 0x7fff0b6e3330) = -1 ENOTTY (Inappropriate ioctl for device)
lseek(3, 0, SEEK_CUR) = 0
read(3, "#!/bin/bash\n\necho \"Hello Unix & Linux!\"\n", 80) = 40
lseek(3, 0, SEEK_SET) = 0
getrlimit(RLIMIT_NOFILE, {rlim_cur=1024, rlim_max=4*1024}) = 0
fcntl(255, F_GETFD) = -1 EBADF (Bad file descriptor)
dup2(3, 255) = 255
close(3)
...
Setelah file dibaca, kemudian dieksekusi:
...
read(255, "#!/bin/bash\n\necho \"Hello Unix & Linux!\"\n", 40) = 40
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 3), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc0b38ba000
write(1, "Hello Unix & Linux!\n", 20) = 20
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(255, "", 40) = 0
exit_group(0) = ?
Di atas kita dapat dengan jelas melihat bahwa seluruh skrip tampaknya dibaca sebagai satu kesatuan, dan kemudian dieksekusi setelahnya. Jadi itu akan "muncul" setidaknya dalam kasus Bash yang membaca file, dan kemudian mengeksekusinya. Jadi menurut Anda Anda dapat mengedit skrip saat sedang berjalan?
CATATAN: Namun, jangan! Baca terus untuk memahami mengapa Anda tidak boleh mengutak-atik file skrip yang sedang berjalan.
Bagaimana dengan penerjemah lain?
Tapi pertanyaan Anda sedikit melenceng. Bukan Linux yang harus memuat konten file, itu adalah juru bahasa yang memuat konten, jadi tergantung bagaimana juru bahasa mengimplementasikan apakah itu memuat file seluruhnya atau dalam blok atau baris pada satu waktu.
Jadi mengapa kita tidak bisa mengedit file?
Namun jika Anda menggunakan skrip yang jauh lebih besar, Anda akan melihat bahwa pengujian di atas agak menyesatkan. Faktanya, sebagian besar penerjemah memuat file mereka dalam blok. Ini cukup standar dengan banyak alat Unix tempat mereka memuat blok file, memprosesnya, dan kemudian memuat blok lain. Anda dapat melihat perilaku ini dengan T&J U&L yang saya tulis beberapa waktu lalu tentang grep
, berjudul:Berapa banyak teks yang dikonsumsi grep/egrep setiap kali?.
Contoh
Katakanlah kita membuat skrip shell berikut.
$ (
echo '#!/bin/bash';
for i in {1..100000}; do printf "%s\n" "echo \"$i\""; done
) > ascript.bash;
$ chmod +x ascript.bash
Menghasilkan file ini:
$ ll ascript.bash
-rwxrwxr-x. 1 saml saml 1288907 Mar 23 18:59 ascript.bash
Yang berisi jenis konten berikut:
$ head -3 ascript.bash ; echo "..."; tail -3 ascript.bash
#!/bin/bash
echo "1"
echo "2"
...
echo "99998"
echo "99999"
echo "100000"
Sekarang ketika Anda menjalankan ini menggunakan teknik yang sama di atas dengan strace
:
$ strace -s 2000 -o strace_ascript.log ./ascript.bash
...
read(255, "#!/bin/bash\necho \"1\"\necho \"2\"\necho \"3\"\necho \"4\"\necho \"5\"\necho \"6\"\necho \"7\"\necho \"8\"\necho \"9\"\necho \"10\"\necho
...
...
\"181\"\necho \"182\"\necho \"183\"\necho \"184\"\necho \"185\"\necho \"186\"\necho \"187\"\necho \"188\"\necho \"189\"\necho \"190\"\necho \""..., 8192) = 8192
Anda akan melihat bahwa file sedang dibaca dengan peningkatan 8KB, jadi Bash dan shell lain kemungkinan tidak akan memuat file secara keseluruhan, melainkan membacanya dalam blok.
Referensi
- The #! keajaiban, detail tentang mekanisme shebang/hash-bang pada berbagai rasa Unix
Ini lebih bergantung pada shell daripada bergantung pada OS.
Bergantung pada versinya, ksh
baca skrip sesuai permintaan dengan blok 8k atau 64k byte.
bash
membaca skrip baris demi baris. Namun, mengingat fakta bahwa baris dapat memiliki panjang yang sewenang-wenang, ia membaca setiap kali 8176 byte dari awal baris berikutnya untuk diurai.
Ini untuk konstruksi sederhana, yaitu rangkaian perintah sederhana.
Jika perintah terstruktur shell digunakan (kasus jawaban yang diterima terlewatkan untuk dipertimbangkan ) seperti for/do/done
lingkaran, sebuah case/esac
switch, dokumen di sini, subkulit yang diapit oleh tanda kurung, definisi fungsi, dll. dan kombinasi apa pun di atas, juru bahasa Shell membaca hingga akhir konstruksi untuk terlebih dahulu memastikan tidak ada kesalahan sintaksis.
Hal ini agak tidak efisien karena kode yang sama dapat dibaca berkali-kali tetapi dikurangi dengan fakta bahwa konten ini biasanya di-cache.
Apa pun penerjemah shell-nya, sangat tidak bijaksana untuk memodifikasi skrip shell saat sedang dieksekusi karena shell bebas untuk membaca kembali bagian mana pun dari skrip dan ini dapat menyebabkan kesalahan sintaksis yang tidak terduga jika tidak sinkron.
Perhatikan juga bahwa bash mungkin mogok dengan pelanggaran segmentasi saat tidak dapat menyimpan konstruksi skrip yang terlalu besar yang dapat dibaca oleh ksh93 dengan sempurna.
Itu tergantung pada bagaimana juru bahasa menjalankan skrip bekerja. Yang dilakukan kernel hanyalah memperhatikan file yang akan dieksekusi dimulai dengan #!
, pada dasarnya menjalankan sisa baris sebagai program dan memberikannya argumen yang dapat dieksekusi. Jika juru bahasa yang tercantum di sana membaca file itu baris demi baris (seperti yang dilakukan shell interaktif dengan apa yang Anda ketikkan), itulah yang Anda dapatkan (tetapi struktur loop multi-baris dibaca dan disimpan untuk diulang); jika penerjemah menyeruput file ke dalam memori, memprosesnya (mungkin mengkompilasinya ke representasi perantara, seperti yang dilakukan Perl dan Pyton) file tersebut dibaca secara penuh sebelum dijalankan.
Sementara itu, jika Anda menghapus file, file tidak akan dihapus hingga penerjemah menutupnya (seperti biasa, file hilang saat referensi terakhir, baik itu entri direktori atau proses yang membuatnya tetap terbuka) menghilang.