GNU/Linux >> Belajar Linux >  >> Linux

Bagaimana Linux menangani skrip shell?

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.


Linux
  1. Cara mengenkripsi file dengan gocryptfs di Linux

  2. Cara Mengganti Shell di Linux

  3. Cara mengubah kata dalam file dengan skrip shell linux

  1. Bagaimana saya menggunakan Vagrant dengan libvirt

  2. Dasar-dasar Linux:Cara Mengunduh File di Shell Dengan Wget

  3. Bagaimana saya bisa melakukan pembagian dengan variabel di shell Linux?

  1. Linux – Bagaimana Load Average Bekerja Dengan CPU Modern?

  2. Bagaimana Mengurai Json Dengan Shell Scripting Di Linux?

  3. Bagaimana cara mengganti nama file dengan spasi menggunakan shell Linux?