Pertanyaan Mengapa orang menulis #! / Usr / bin / env python shebang pada baris pertama dari skrip Python?


Sepertinya saya suka file berjalan sama tanpa garis itu.


820
2018-03-11 23:50


asal


Jawaban:


Jika Anda memiliki beberapa versi Python yang diinstal, /usr/bin/env akan memastikan interpreter yang digunakan adalah yang pertama di lingkungan Anda $PATH. Alternatifnya adalah dengan hardcode sesuatu seperti #!/usr/bin/python; tidak apa-apa, tapi kurang fleksibel.

Di Unix, sebuah dapat dieksekusi file yang dimaksudkan untuk ditafsirkan dapat menunjukkan interpreter apa yang digunakan dengan memiliki #! pada awal baris pertama, diikuti oleh penerjemah (dan bendera apa pun yang diperlukan).

Jika Anda berbicara tentang platform lain, tentu saja, aturan ini tidak berlaku (tapi itu "shebang line" tidak membahayakan, dan akan membantu jika Anda pernah menyalin script itu ke platform dengan basis Unix, seperti Linux, Mac, dll).


902
2018-03-11 23:52



Itu disebut garis shebang. Sebagai Entri Wikipedia menjelaskan:

Dalam komputasi, shebang (juga disebut hashbang, hashpling, pound bang, atau crunchbang) mengacu pada karakter "#!" ketika mereka adalah dua karakter pertama dalam arahan penerjemah sebagai baris pertama dari file teks. Dalam sistem operasi mirip Unix, pemuat program mengambil dua karakter ini sebagai indikasi bahwa file adalah skrip, dan mencoba menjalankan skrip tersebut menggunakan interpreter yang ditentukan oleh sisa baris pertama dalam file.

Lihat juga Entri FAQ Unix.

Bahkan pada Windows, di mana garis shebang tidak menentukan interpreter yang akan dijalankan, Anda dapat memberikan opsi kepada juru bahasa dengan menentukannya pada garis shebang. Saya merasa berguna untuk menyimpan garis generik shebang dalam skrip satu-off (seperti yang saya tulis ketika menjawab pertanyaan di SO), jadi saya bisa dengan cepat menguji mereka pada Windows dan ArchLinux.

Itu utilitas env memungkinkan Anda untuk menjalankan perintah di jalur:

Argumen yang tersisa pertama menentukan nama program untuk memanggil; itu dicari sesuai dengan PATH variabel lingkungan. Argumen yang tersisa dilewatkan sebagai argumen untuk program itu.


222
2018-03-11 23:52



Memperluas sedikit pada jawaban yang lain, inilah sedikit contoh bagaimana skrip baris perintah Anda dapat bermasalah dengan penggunaan yang tidak hati-hati /usr/bin/env garis shebang:

$ /usr/local/bin/python -V
Python 2.6.4
$ /usr/bin/python -V
Python 2.5.1
$ cat my_script.py 
#!/usr/bin/env python
import json
print "hello, json"
$ PATH=/usr/local/bin:/usr/bin
$ ./my_script.py 
hello, json
$ PATH=/usr/bin:/usr/local/bin
$ ./my_script.py 
Traceback (most recent call last):
  File "./my_script.py", line 2, in <module>
    import json
ImportError: No module named json

Modul json tidak ada di Python 2.5.

Salah satu cara untuk mencegah masalah semacam itu adalah dengan menggunakan nama perintah python berversi yang biasanya diinstal dengan sebagian besar Python:

$ cat my_script.py 
#!/usr/bin/env python2.6
import json
print "hello, json"

Jika Anda hanya perlu membedakan antara Python 2.x dan Python 3.x, rilis terbaru dari Python 3 juga menyediakan a python3 nama:

$ cat my_script.py 
#!/usr/bin/env python3
import json
print("hello, json")

135
2018-03-12 00:35



Untuk menjalankan skrip python, kita perlu memberi tahu shell tiga hal:

  1. Bahwa file itu adalah skrip
  2. Interpreter mana yang ingin kita jalankan skripnya
  3. Jalan kata interpreter

Shebang itu #! menyelesaikan (1.). Shebang dimulai dengan # karena #karakter adalah penanda komentar dalam banyak bahasa scripting. Oleh karena itu, isi garis shebang secara otomatis diabaikan oleh penerjemah.

Itu env perintah selesai (2.) dan (3.). Untuk mengutip "grawity,"

Penggunaan umum dari env komando adalah meluncurkan penerjemah, dengan membuat   penggunaan fakta bahwa env akan mencari $ PATH untuk perintah yang diceritakan   peluncuran. Karena garis shebang membutuhkan jalur absolut untuk menjadi   ditentukan, dan karena lokasi berbagai interpreter (perl, bash,   python) dapat bervariasi, biasanya digunakan:

#!/usr/bin/env perldaripada mencoba menebak apakah itu   / bin / perl, / usr / bin / perl, / usr / local / bin / perl, / usr / local / pkg / perl,   / fileserver / usr / bin / perl, atau / home / MrDaniel / usr / bin / perl pada pengguna   sistem...

Di sisi lain, env hampir selalu berada di / usr / bin / env. (Kecuali dalam   kasus saat tidak; beberapa sistem mungkin menggunakan / bin / env, tapi itu a   cukup langka dan hanya terjadi pada sistem non-Linux.)


78
2018-03-26 00:07



Secara teknis, dengan Python, ini hanya sebuah baris komentar.

Baris ini hanya digunakan jika Anda menjalankan skrip py dari cangkangnya (dari baris perintah). Ini dikenal sebagai "Peristiwa! ", dan digunakan dalam berbagai situasi, tidak hanya dengan skrip Python.

Di sini, ia menginstruksikan shell untuk memulai versi spesifik Python (untuk mengurus sisa file.


38
2018-03-11 23:58



Mungkin pertanyaan Anda dalam pengertian ini:

Jika Anda ingin menggunakan: $python myscript.py

Anda tidak perlu baris itu sama sekali. Sistem akan memanggil python dan kemudian python interpreter akan menjalankan skrip Anda.

Tetapi jika Anda berniat menggunakan: $./myscript.py

Memanggilnya langsung seperti program normal atau skrip bash, Anda perlu menulis baris tersebut untuk menentukan sistem yang digunakan program untuk menjalankannya, (dan juga membuatnya dapat dieksekusi dengan chmod 755)


37
2018-01-17 11:13



Alasan utama untuk melakukan ini adalah membuat skrip portabel di lingkungan sistem operasi.

Misalnya di bawah mingw, skrip python menggunakan:

#!/c/python3k/python 

dan di bawah distribusi GNU / Linux adalah:

#!/usr/local/bin/python 

atau

#!/usr/bin/python

dan di bawah sistem terbaik unix sw / hw semua (OS / X), itu adalah:

#!/Applications/MacPython 2.5/python

atau di FreeBSD:

#!/usr/local/bin/python

Namun semua perbedaan ini dapat menjadikan skrip portabel di semua dengan menggunakan:

#!/usr/bin/env python

34
2017-07-20 22:34



Itu exec system call dari kernel Linux mengerti shebangs (#!) secara asli

Ketika Anda melakukannya di bash:

./something

di Linux, ini memanggil exec panggilan sistem dengan jalur ./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]! = '!'))

Ini membaca byte pertama file, dan membandingkannya #!.

Jika itu benar, maka sisa baris ini diurai oleh kernel Linux, yang membuat panggilan exec lain dengan jalur /usr/bin/env python dan file saat ini sebagai argumen pertama:

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

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

Dan ya, Anda dapat membuat pengulangan tanpa batas dengan:

#!/a

dan file yang dapat dieksekusi di /a

#! hanya kebetulan manusia yang dapat dibaca, tetapi itu tidak diperlukan.

Jika file dimulai dengan byte berbeda, maka exec panggilan sistem akan menggunakan penangan yang berbeda. Handler built-in lain yang paling penting adalah untuk 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 bisa dibaca oleh manusia .ELF). Ini membaca file ELF, memasukkannya ke dalam memori dengan benar, dan memulai proses baru dengannya. Lihat juga: Bagaimana kernel mendapatkan file biner yang dapat dieksekusi berjalan di bawah linux?

Akhirnya, Anda dapat menambahkan penangan shebang Anda sendiri dengan binfmt_misc mekanisme. Misalnya, Anda dapat menambahkan handler kustom untuk .jar file. Mekanisme ini bahkan mendukung penangan oleh ekstensi file. Aplikasi lain adalah untuk jalankan secara transparan executable dari arsitektur yang berbeda dengan QEMU.

Saya tidak berpikir POSIX menentukan shebang bagaimanapun: https://unix.stackexchange.com/a/346214/32558 , meskipun itu disebutkan dalam bagian rasional, dan dalam bentuk "jika skrip yang dapat dijalankan didukung oleh sistem, sesuatu dapat terjadi".


23
2017-12-02 18:29