Apakah #! / Bin / sh dibaca oleh interpreter?

66

Dalam bashatau sh, saya kira apa yang dimulai dengan #sebuah komentar .

Namun dalam bashskrip kami menulis:

#!/bin/bash

Dan dalam skrip Python, ada:

#!/bin/python

Apakah ini berarti bahwa #dengan sendirinya adalah komentar sedangkan #!tidak?

Gaurav Sharma
sumber
1
Dan begitu Anda mulai melihat profil Apparmor, Anda akan melihat #include. Di sana juga, #itu tidak dimaksudkan sebagai komentar.
4
@ vasa1 Tapi poin kunci yang sering tidak dihargai tentang baris hashbang di awal skrip shell adalah bahwa mereka adalah komentar .
Eliah Kagan

Jawaban:

100

The #!line digunakan sebelum script dijalankan, maka diabaikan ketika script berjalan.

Anda bertanya apa perbedaan antara garis shebang dan komentar biasa.

Baris yang diawali dengan #!komentar sama banyaknya dengan baris lain yang dimulai #. Ini benar jika #!ini adalah baris pertama file, atau di mana saja. #!/bin/sh memiliki efek , tetapi tidak dibaca oleh penerjemah itu sendiri .

#bukan komentar dalam semua bahasa pemrograman tetapi, seperti yang Anda tahu, ini adalah komentar di shell gaya Bourne termasuk shdan bash(serta sebagian besar shell gaya non-Bourne, seperti csh). Ini juga komentar dalam Python . Dan itu adalah komentar dalam berbagai file konfigurasi yang sebenarnya bukan skrip (seperti /etc/fstab).

Misalkan skrip shell dimulai dengan #!/bin/sh. Itu adalah komentar, dan penerjemah (shell) mengabaikan semua yang ada di baris setelah #karakter.

Tujuan dari suatu #!garis bukanlah untuk memberikan informasi kepada penerjemah. Tujuan dari #!jalur ini adalah untuk memberi tahu sistem operasi (atau proses apa pun yang meluncurkan penerjemah) apa yang harus digunakan sebagai penerjemah .

  • Jika Anda menjalankan skrip sebagai file yang dapat dieksekusi, misalnya, dengan menjalankan ./script.sh, sistem berkonsultasi dengan baris pertama untuk melihat apakah dimulai dengan #!, diikuti oleh nol atau lebih banyak ruang, diikuti oleh perintah. Jika ya, ia menjalankan perintah itu dengan nama skrip sebagai argumennya. Dalam contoh ini, ini berjalan /bin/sh script.sh(atau, secara teknis, /bin/sh ./script.sh).

  • Jika Anda mengaktifkan skrip dengan secara eksplisit memanggil juru bahasa, #!garis itu tidak pernah dikonsultasikan. Jadi, jika Anda menjalankan sh script.sh, baris pertama tidak berpengaruh. Jika script2.shbaris pertama adalah #!/usr/games/nibbles, menjalankan sh script2.shtidak akan mencoba membuka skrip di nibbles(tetapi ./script2.shakan).

Anda akan melihat bahwa dalam kedua kasus itu ekstensi skrip ( .sh), jika ada, berdampak pada bagaimana skrip dijalankan. Dalam sistem seperti Unix, ini biasanya tidak mempengaruhi bagaimana skrip dijalankan. Pada beberapa sistem lain, seperti Windows, #!garis shebang mungkin diabaikan sepenuhnya oleh sistem, dan ekstensi mungkin menentukan apa yang menjalankan skrip. (Ini tidak berarti Anda harus memberikan ekstensi skrip Anda, tetapi itu adalah salah satu alasan mengapa jika Anda melakukannya, itu harus benar.)

#!dipilih untuk melayani tujuan ini justru karena # memulai komentar. The #!line untuk sistem, tidak interpreter, dan itu harus diabaikan oleh interpreter.

Garis Shebang untuk Skrip Bash

Anda (awalnya) mengatakan Anda gunakan #!/bin/shuntuk bashskrip. Anda hanya harus melakukan itu jika skrip tidak memerlukan bashekstensi apa pun - shharus dapat menjalankan skrip. shtidak selalu merupakan symlink ke bash. Seringkali, termasuk pada semua sistem Debian dan Ubuntu terbaru dari jarak jauh , shadalah symlink ke dash.

Baris Shebang untuk Skrip Python

Anda juga mengatakan (dalam versi pertama pertanyaan Anda, sebelum diedit) bahwa Anda memulai skrip Python Anda #!/bin/sh read by the interpretor. Jika Anda benar-benar bermaksud demikian, maka Anda harus berhenti melakukannya. Jika hello.pydimulai dengan baris itu, menjalankan ./hello.pydijalankan:

/bin/sh read by the interpretor hello.py

/bin/shakan mencoba untuk mengeksekusi skrip yang disebut read(dengan by the interpretor hello.pyargumennya), tidak readakan (semoga) tidak ditemukan, dan skrip Python Anda tidak akan pernah dilihat oleh juru bahasa Python.

Jika Anda membuat kesalahan ini tetapi tidak memiliki masalah yang saya jelaskan, Anda mungkin menggunakan skrip Python Anda dengan secara eksplisit menentukan penerjemah (mis., python hello.py), Sehingga baris pertama diabaikan. Saat Anda mendistribusikan skrip Anda ke orang lain, atau menggunakannya beberapa saat kemudian, mungkin tidak jelas bahwa ini perlu bagi mereka untuk bekerja. Yang terbaik untuk memperbaikinya sekarang. Atau setidaknya menghapus baris pertama sepenuhnya, sehingga ketika mereka gagal dijalankan dengan ./pesan kesalahan akan masuk akal.

Untuk skrip Python, jika Anda tahu di mana juru bahasa Python berada (atau akan menjadi), Anda dapat menulis #!baris dengan cara yang sama:

#!/usr/bin/python

Atau, jika skrip Python 3, Anda harus menentukan python3, karena pythonhampir selalu Python 2 :

#!/usr/bin/python3

Namun, masalahnya adalah bahwa sementara /bin/shseharusnya selalu ada, dan /bin/bashhampir selalu ada pada sistem di mana bashdatang dengan OS, Python mungkin ada di berbagai tempat.

Oleh karena itu, banyak programmer Python yang menggunakan ini:

#!/usr/bin/env python

(Atau #!/usr/bin/env python3untuk Python 3.)

Ini membuat skrip mengandalkan envberada di "tempat yang tepat" daripada mengandalkan pythonberada di tempat yang tepat. Itu hal yang baik, karena:

  • envhampir selalu terletak di /usr/bin.
  • Pada sebagian besar sistem, mana yang python harus menjalankan skrip Anda adalah yang muncul pertama kali di PATH. Dimulai hello.pydengan #!/usr/bin/env pythonmake ./hello.pyrun /usr/bin/env python hello.py, yang (hampir) setara dengan running python hello.py.

Alasan Anda tidak dapat menggunakan #!pythonadalah:

  • Anda ingin penerjemah yang ditentukan diberikan oleh jalur absolut (yaitu, dimulai dengan /).
  • Proses panggilan akan dijalankan python di direktori saat ini . Mencari path ketika perintah tidak mengandung garis miring adalah perilaku shell tertentu.

Kadang-kadang sebuah Python atau skrip lain yang bukan skrip shell akan memiliki garis shebang dimulai dengan di #!/bin/sh ...mana ...beberapa kode lainnya. Ini kadang-kadang benar, karena ada beberapa cara untuk memanggil shell Bourne-compatible ( sh) dengan argumen untuk membuatnya memanggil juru bahasa Python. (Salah satu argumen mungkin akan berisi python.) Namun, untuk sebagian besar tujuan, #!/usr/bin/env pythonlebih sederhana, lebih elegan, dan lebih mungkin untuk bekerja seperti yang Anda inginkan.

Garis Shebang dalam Bahasa Lainnya

Banyak bahasa pemrograman dan skrip, dan beberapa format file lainnya, digunakan #sebagai komentar. Untuk salah satu dari mereka, file dalam bahasa dapat dijalankan oleh program yang menganggapnya sebagai argumen dengan menentukan program di baris pertama setelahnya #!.

Dalam beberapa bahasa pemrograman, #biasanya bukan komentar, tetapi sebagai kasus khusus, baris pertama diabaikan jika dimulai dengan #!. Ini memfasilitasi penggunaan #!sintaks meskipun #tidak membuat baris komentar.

Garis Shebang untuk File yang Tidak Berjalan Sebagai Skrip

Meskipun kurang intuitif, file apa pun yang format file dapat mengakomodasi baris pertama dimulai dengan #!diikuti oleh path lengkap dari executable dapat memiliki garis shebang. Jika Anda melakukan ini, dan file ditandai dapat dieksekusi, maka Anda dapat menjalankannya seperti sebuah program ... menyebabkannya dibuka seperti dokumen.

Beberapa aplikasi menggunakan perilaku ini dengan sengaja. Misalnya, di VMware, .vmxfile menentukan mesin virtual. Anda dapat "menjalankan" mesin virtual seolah-olah itu adalah skrip karena file-file ini ditandai dapat dieksekusi dan memiliki garis shebang yang menyebabkan mereka dibuka dalam utilitas VMware.

Garis Shebang untuk File yang Tidak Berjalan sebagai Skrip tetapi Bertindak Seperti Skrip

rmmenghapus file. Ini bukan bahasa scripting. Namun, file yang dimulai #!/bin/rmdan ditandai dapat dieksekusi dapat dijalankan, dan ketika Anda menjalankannya, rmdipanggil, dihapus.

Ini sering dikonseptualisasikan sebagai "file menghapus dirinya sendiri." Tetapi file tersebut tidak benar-benar berjalan sama sekali. Ini lebih seperti situasi yang dijelaskan di atas untuk .vmxfile.

Namun, karena #!baris memfasilitasi jalannya perintah sederhana (termasuk argumen baris perintah), Anda dapat melakukan beberapa skrip dengan cara ini. Sebagai contoh sederhana dari "skrip" yang lebih canggih daripada #!/bin/rm, pertimbangkan:

#!/usr/bin/env tee -a

Ini mengambil input pengguna secara interaktif, menggaungkannya kembali ke baris demi baris pengguna, dan menambahkannya ke akhir file "skrip".

Berguna? Tidak terlalu. Secara konseptual menarik? Sama sekali! Iya. (Agak.)

Konsep Pemrograman / Skrip yang Mirip (hanya untuk bersenang-senang)

Eliah Kagan
sumber
@Rinzwind Thx! (Btw jawaban ini tidak berasal dari tempat lain, jika itu yang Anda tanyakan.)
Eliah Kagan
@Rinzwind Jangan khawatir, dengan 8 upvotes setelah 1 jam kemungkinan akan meningkat lebih jauh :-)
guntbert
1
Jika selalu diabaikan, lalu apa yang dilakukan -xbendera Python ?
gerrit
4
@ kritik Pertanyaan bagus. Dalam bahasa apa pun di mana intepreter / kompiler melaporkan pesan dengan nomor baris, isi komentar diabaikan, tetapi baris komentar masih dihitung . Menambahkan komentar atau baris kosong sebelum satu baris kode masih menghasilkan baris kode yang memiliki nomor baris yang bertambah. -x"lewati [s] baris pertama ..." baris ke-2 diberi nomor 1alih-alih 2, baris ke-3 2alih-alih 3, dll. Inilah sebabnya Anda tidak boleh menggunakan bendera itu. ;) -xadalah untuk skrip pada OS non-Unix-like yang tidak memiliki sintaks seperti shebang yang dimulai dengan #(sehingga bukan komentar Python).
Eliah Kagan
4
Dalam Perl, jika penerjemah dimulai secara langsung ( perl script.plvs. ./script.pl) maka penerjemah akan membaca baris shebang ke parse flags seperti -w. Namun tidak disarankan untuk mengandalkan fitur ini.
Stop Harming Monica
7

Shebang adalah urutan karakter yang terdiri dari tanda nomor karakter dan tanda seru (misalnya "#!") Ketika itu terjadi sebagai dua karakter awal pada baris awal naskah.

Di bawah sistem operasi * nix, ketika skrip dimulai dengan shebang dijalankan, program loader mem-parsing sisa baris awal skrip sebagai arahan juru bahasa; program penerjemah tertentu dijalankan sebagai gantinya, meneruskannya sebagai argumen jalur yang awalnya digunakan ketika mencoba menjalankan skrip. Sebagai contoh, jika sebuah skrip dinamai dengan path "path / to / your-script", dan itu dimulai dengan baris berikut:

#!/bin/sh

kemudian program loader diinstruksikan untuk menjalankan program "/ bin / sh" sebagai gantinya misalnya Bourne shell atau shell yang kompatibel, melewati "path / to / your-script" sebagai argumen pertama.

Oleh karena itu, skrip dinamai dengan path "path / to / python-script" dan dimulai dengan baris berikut:

#!/bin/python

maka program yang dimuat diinstruksikan untuk menjalankan program "/ bin / python" sebagai gantinya misal juru bahasa Python, dengan meneruskan "path / ke / python-script" sebagai argumen pertama.

Singkatnya "#" akan mengomentari satu baris sementara urutan karakter "#!" terjadi sebagai dua karakter pertama pada baris awal naskah memiliki makna yang diuraikan di atas.

Untuk detail, lihat Mengapa beberapa skrip memulai dengan #! ...?

Sumber: Beberapa bagian dari jawaban ini berasal (dengan sedikit modifikasi) dari Shebang (Unix) di Wikipedia bahasa Inggris (oleh kontributor Wikipedia ). Artikel ini dilisensikan di bawah CC-BY-SA 3.0 , sama dengan konten pengguna di AU, jadi derivasi ini diizinkan dengan atribusi.

Goran Miskovic
sumber
4

#!disebut shebangketika itu terjadi sebagai dua karakter awal pada baris awal skrip. Ini digunakan dalam skrip untuk menunjukkan penerjemah untuk dieksekusi. Ini shebanguntuk sistem operasi (kernel), bukan untuk shell; jadi itu tidak akan ditafsirkan sebagai komentar.

Courtesy: http://en.wikipedia.org/wiki/Shebang_%28Unix%29

Secara umum, jika sebuah file dapat dieksekusi, tetapi sebenarnya bukan program yang dapat dieksekusi (biner), dan garis tersebut ada, program tersebut ditentukan setelah #! dimulai dengan nama script dan semua argumennya. Dua karakter ini # dan! harus dua byte pertama dalam file!

Info Lengkap: http://wiki.bash-hackers.org/scripting/basics#the_shebang

disajikan89
sumber
0

Tidak, ini hanya digunakan oleh execsystem call dari kernel Linux, dan diperlakukan sebagai komentar oleh penerjemah

Ketika Anda melakukannya di bash:

./something

di Linux, ini memanggil execsystem call dengan path ./something.

Baris kernel ini dipanggil pada file yang diteruskan ke exec: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25

if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))

Itu membaca byte pertama file, dan membandingkannya #!.

Jika perbandingannya benar, maka seluruh baris diuraikan oleh kernel Linux, yang membuat execpanggilan lain dengan path /usr/bin/env pythondan file saat ini sebagai argumen pertama:

/usr/bin/env python /path/to/script.py

dan ini berfungsi untuk bahasa skrip apa pun yang digunakan #sebagai karakter komentar.

Dan ya, Anda dapat membuat loop tanpa batas dengan:

printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a

Bash mengenali kesalahan:

-bash: /a: /a: bad interpreter: Too many levels of symbolic links

#! Kebetulan bisa dibaca manusia, tapi itu tidak wajib.

Jika file dimulai dengan byte yang berbeda, maka execpanggilan sistem akan menggunakan penangan yang berbeda. Handler internal terpenting lainnya adalah file yang dapat dieksekusi ELF: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 yang memeriksa byte 7f 45 4c 46(yang juga merupakan manusia dapat dibaca untuk .ELF). Mari kita konfirmasi dengan membaca 4 byte pertama /bin/ls, yang merupakan executable ELF:

head -c 4 "$(which ls)" | hd 

keluaran:

00000000  7f 45 4c 46                                       |.ELF|
00000004                                                                 

Jadi ketika kernel melihat byte-byte itu, ia mengambil file ELF, memasukkannya ke dalam memori dengan benar, dan memulai proses baru dengannya. Lihat juga: https://stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861

Akhirnya, Anda dapat menambahkan penangan shebang Anda sendiri dengan binfmt_miscmekanismenya. Misalnya, Anda dapat menambahkan penangan khusus untuk .jarfile . Mekanisme ini bahkan mendukung penangan melalui ekstensi file. Aplikasi lain adalah untuk menjalankan executable dari arsitektur yang berbeda dengan QEMU .

Saya tidak berpikir POSIX menentukan shebangs: https://unix.stackexchange.com/a/346214/32558 , meskipun ia menyebutkan bagian rasional, dan dalam bentuk "jika skrip yang dapat dieksekusi didukung oleh sistem, sesuatu mungkin terjadi".

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
sumber