Haruskah saya menaruh #! (Shebang) dalam skrip Python, dan bagaimana bentuknya?

830

Haruskah saya menaruh shebang di skrip Python saya? Dalam bentuk apa?

#!/usr/bin/env python 

atau

#!/usr/local/bin/python

Apakah ini sama-sama portabel? Bentuk mana yang paling banyak digunakan?

Catatan: yang tornado proyek menggunakan peristiwa tersebut. Di sisi lainproyek Django tidak.

treecoder
sumber
70
Yang kedua tidak portabel dan akan gagal pada banyak komputer, jika tidak kebanyakan.
Dietrich Epp
4
Bagaimana #!/usr/bin/pythondibandingkan dengan opsi pertama? Saya melihat ini dalam banyak contoh kode. Sunting: Mungkin ini jawabannya .. stackoverflow.com/a/2429517/1156245
geotheory
1
Saya katakan selalu menggunakannya, Kenapa? "Zen Of Python" - Baris 2 - "Eksplisit lebih baik daripada implisit." python.org/dev/peps/pep-0020
JayRizzo
2
Terus terang, tidak ada yang "benar", karena Anda sebagai penulis tidak tahu di mana versi Python yang benar akan berada ketika skrip dijalankan. Seharusnya pekerjaan installer untuk menambahkan shebang yang benar.
chepner

Jawaban:

1117

Baris shebang dalam skrip apa pun menentukan kemampuan skrip untuk dieksekusi seperti yang dapat dieksekusi mandiri tanpa mengetikkan pythonsebelumnya di terminal atau ketika mengklik dua kali dalam file manager (bila dikonfigurasi dengan benar). Tidak perlu tetapi umumnya diletakkan di sana sehingga ketika seseorang melihat file dibuka di editor, mereka segera tahu apa yang mereka lihat Namun, garis shebang mana yang Anda gunakan IS penting.

Penggunaan yang benar untuk skrip Python 3 adalah:

#!/usr/bin/env python3

Ini default ke versi 3. terbaru. Untuk Python 2.7.estest digunakan python2sebagai pengganti python3.

Berikut ini TIDAK boleh digunakan (kecuali untuk kasus yang jarang Anda menulis kode yang kompatibel dengan Python 2.x dan 3.x):

#!/usr/bin/env python

Alasan untuk rekomendasi ini, diberikan dalam PEP 394 , adalah yang pythondapat merujuk ke python2atau python3pada sistem yang berbeda. Saat ini mengacu python2pada sebagian besar distribusi, tetapi itu mungkin akan berubah di beberapa titik.

Juga, JANGAN Gunakan:

#!/usr/local/bin/python

"python dapat diinstal di / usr / bin / python atau / bin / python dalam kasus itu, # di atas akan gagal."

- "#! / usr / bin / env python" vs "#! / usr / local / bin / python"

GlassGhost
sumber
4
@ EliasVanOotegem Jika Anda tidak dapat memastikan bahwa python akan ditemukan /usr/binmaka bagaimana Anda dapat yakin bahwa envakan ditemukan /usr/bin. Jika python dipasang di tempat non-standar maka kemungkinan itu berarti bahwa python diatur dengan cara non-standar dan sebagai hasilnya skrip harus gagal dengan cepat. Berbeda dengan membuat asumsi tentang sifat-sifat interpreter python dan berharap yang terbaik.
Bukit pasir
65
@ Bukit: envakan selalu ditemukan di /usr/bin/, dan tugasnya adalah untuk menemukan tempat sampah (seperti python) menggunakan PATH. Tidak peduli bagaimana python diinstal, pathnya akan ditambahkan ke variabel ini, dan envakan menemukannya (jika tidak, python tidak diinstal). Itu pekerjaan env, itulah alasan mengapa itu ada. Ini adalah hal yang memperingatkan lingkungan (mengatur variabel env, termasuk jalur instal, dan menyertakan jalur). Orang-orang selalu mengerti bahwa perintah ini hanya dapat berfungsi jika selalu ditemukan di tempat yang sama. Itu hanya diberikan
Elias Van Ootegem
3
@ JSFSebastian: Anda benar, tidak dijamin, atau dipaksakan oleh standar POSIX. Saya berasumsi itu karena salah satu versi IEEE nanti memang mengandung beberapa hal lingkungan. Either way: tidak, /usr/bin/envtidak dijamin oleh standar apa pun, selain aturan yang diadopsi secara luas (universal?) ...
Elias Van Ootegem
6
Jika Anda menggunakan virtualenv, #! / Usr / local / bin / python, meskipun ada, salah.
nullas
6
Satu masalah dengan ini: menurut PEP394 kita hanya boleh menggunakan pythonexecutable ketika skrip kompatibel dengan Python 2 dan Python 3. Jika tidak, itu harus menunjuk ke pilihan yang sesuai dari python2dan python3.
amiller27
67

Ini benar-benar hanya masalah selera. Menambahkan shebang berarti orang dapat menjalankan skrip secara langsung jika mereka mau (dengan asumsi itu ditandai sebagai executable); menghilangkannya berarti pythonharus dipanggil secara manual.

Hasil akhir dari menjalankan program tidak terpengaruh; itu hanya pilihan sarana.

Amber
sumber
3
Hanya itu - tidak masalah sisi mana yang Anda ambil karena tidak ada sisi "kanan". Ini adalah keputusan yang sepenuhnya subjektif.
Amber
5
Tidak lebih dari keputusan sepele lainnya. en.wikipedia.org/wiki/Parkinson's_Law_of_Triviality
Amber
2
Bagaimana saya bisa mengeksekusi file python secara langsung tanpa perintah 'python'?
Zen
5
@ Zen Dengan asumsi Anda memasukkan shebang (#! / Usr / bin / env python) dalam skrip Anda, Anda hanya perlu membuat skrip Anda dapat dieksekusi. Sesuatu seperti chmod a+x [your-script].pyharus membuatnya dapat dieksekusi dan kemudian Anda bisa memanggil ./[your-script.py]shell.
skålfyfan
9
Sebagai jawaban dengan GlassGhost menunjukkan, ada adalah keuntungan konkret untuk termasuk itu selain rasa: itu membuat jelas bagi pembaca masa depan file bahwa mereka sedang membaca script executable, bukan file yang dimaksudkan untuk diimpor. Demikian pula untuk pengubah kontrol akses publik / swasta dalam bahasa yang memilikinya, shebang berguna sebagai dokumentasi serta untuk efek aktualnya, dan dalam beberapa kasus aspek dokumentasi sebenarnya yang paling penting.
Mark Amery
32

Haruskah saya menaruh shebang di skrip Python saya?

Masukkan shebang ke dalam skrip Python untuk menunjukkan:

  • modul ini dapat dijalankan sebagai skrip
  • apakah itu dapat dijalankan hanya pada python2, python3 atau apakah itu Python 2/3 kompatibel
  • pada POSIX, perlu jika Anda ingin menjalankan skrip secara langsung tanpa menjalankan pythonexecutable secara eksplisit

Apakah ini sama-sama portabel? Bentuk mana yang paling banyak digunakan?

Jika Anda menulis shebang secara manual maka selalu gunakan #!/usr/bin/env pythonkecuali Anda memiliki alasan khusus untuk tidak menggunakannya. Formulir ini dipahami bahkan di Windows (peluncur Python).

Catatan: skrip yang terinstal harus menggunakan python yang dapat dieksekusi misalnya, /usr/bin/pythonatau /home/me/.virtualenvs/project/bin/python. Ini buruk jika beberapa alat rusak jika Anda mengaktifkan virtualenv di shell Anda. Untungnya, shebang yang benar dibuat secara otomatis dalam banyak kasus oleh setuptoolsatau alat paket distribusi Anda (pada Windows, setuptoolsdapat menghasilkan .exeskrip wrapper secara otomatis).

Dengan kata lain, jika skrip berada di sumber checkout maka Anda mungkin akan melihat #!/usr/bin/env python. Jika sudah diinstal maka shebang adalah path ke executable python tertentu seperti #!/usr/local/bin/python (CATATAN: Anda seharusnya tidak menulis path dari kategori terakhir secara manual).

Untuk memilih apakah Anda harus menggunakan python,, python2atau python3di shebang, lihat PEP 394 - Perintah "python" pada Sistem Unix-Like :

  • ... pythonharus digunakan pada baris shebang hanya untuk skrip yang sumbernya kompatibel dengan Python 2 dan 3.

  • dalam persiapan untuk perubahan akhirnya pada versi standar Python, hanya skrip Python 2 yang harus diperbarui menjadi sumber yang kompatibel dengan Python 3 atau yang lain untuk digunakan python2dalam baris shebang.

jfs
sumber
3
Jawaban pertama untuk merujuk pada PEP tidak memiliki cukup upvotes. Hah? Apakah ada PEP untuk #!/usr/bin/env pythondirinya sendiri?
binki
Tolong jangan gunakan #!/usr/bin/env python. Tolong jangan menyarankan untuk "selalu menggunakan" #!/usr/bin/env python. Ini adalah hal yang salah untuk dilakukan dalam 99% kasus (alasan yang Anda masukkan dalam jawaban Anda).
Jay Sullivan
1
@JaySullivan, apakah Anda memahami perbedaan antara checkout sumber dan skrip yang diinstal? Saya mendukung saran itu. Ini bekerja dengan baik.
jfs
1
@ jfs: Setelah membaca kembali komentar saya, saya melihat bagaimana saya benar-benar gagal menyampaikan maksud saya. Yang saya maksudkan adalah kebanyakan orang ingin menggunakan 'python2' atau 'python3', bukan 'python'. Apakah akan diselesaikan melalui path lengkap atau env, yang secara teknis adalah pertanyaan OP, Anda telah menjawab dan saya tidak setuju tentang hal itu.
Jay Sullivan
@ JaySullivan Saya setuju. Apakah Anda membaca kutipan dari pep dalam jawabannya. Itu mengatakan hal yang sama.
jfs
15

Jika Anda memiliki lebih dari satu versi Python dan skrip perlu dijalankan di bawah versi tertentu, she-bang dapat memastikan yang tepat digunakan ketika skrip dieksekusi secara langsung, misalnya:

#!/usr/bin/python2.7

Catatan skrip masih bisa dijalankan melalui baris perintah Python lengkap, atau melalui impor, dalam hal ini she-bang diabaikan. Tetapi untuk skrip yang dijalankan secara langsung, ini adalah alasan yang layak untuk menggunakan she-bang.

#!/usr/bin/env python pada umumnya pendekatan yang lebih baik, tetapi ini membantu dengan kasus-kasus khusus.

Biasanya akan lebih baik untuk membuat lingkungan virtual Python, dalam hal ini generik #!/usr/bin/env pythonakan mengidentifikasi contoh Python yang benar untuk virtualenv.

Chris Johnson
sumber
Bukankah ruang akan menyebabkannya gagal?
RandomInsano
1
@ RandomInsano, saya rasa tidak. Spasi tampak cukup umum dan ada banyak bukti di sekitar 'jala ini sebagai penggunaan yang diterima. Namun saya pikir tidak ada ruang mungkin adalah penggunaan yang lebih kanonik.
Chris Johnson
1
Anda pasti benar dalam hal ini. Baru diuji pada bash dan tcsh.
RandomInsano
Hasil whichakan memberi Anda string yang akan bekerja, titik. Anda tidak perlu khawatir tentang nyali apa pun untuk menggunakannya.
SDsolar
10

Anda harus menambahkan shebang jika skrip ini dimaksudkan untuk dieksekusi. Anda juga harus menginstal skrip dengan perangkat lunak penginstalan yang memodifikasi shebang ke sesuatu yang benar sehingga akan bekerja pada platform target. Contohnya adalah distutils dan Distribute.

Lennart Regebro
sumber
1
Anda tidak perlu mengubah #! baris sesudahnya. Untuk itulah / usr / bin / env. Hard-coding terhadap interpreter Python tertentu mungkin lebih berbahaya daripada kebaikan. Sangat rapuh untuk menginstal versi Python lain atau beralih di antara Python distro kami versus instalasi Python khusus.
vog
Di Ubuntu, menggunakan hasil whichakan secara otomatis memilih default yang sedang digunakan oleh perintah sistem dan semacamnya. Ini generik dan sistem mengarahkannya ke instalasi yang tepat.
SDsolar
9

Tujuan dari shebang adalah agar skrip mengenali tipe juru bahasa saat Anda ingin menjalankan skrip dari shell. Sebagian besar, dan tidak selalu, Anda menjalankan skrip dengan memasok penerjemah secara eksternal. Contoh penggunaan:python-x.x script.py

Ini akan berfungsi bahkan jika Anda tidak memiliki deklarator shebang.

Mengapa yang pertama lebih "portabel" karena, /usr/bin/envberisi PATHdeklarasi Anda yang menyumbang semua tujuan di mana executable sistem Anda berada.

CATATAN: Tornado tidak sepenuhnya menggunakan shebang, dan Django tidak menggunakan ini. Ini berbeda dengan bagaimana Anda menjalankan fungsi utama aplikasi Anda.

JUGA: Tidak berbeda dengan Python.

meson10
sumber
8

Kadang-kadang, jika jawabannya sangat tidak jelas (Maksudku Anda tidak dapat memutuskan apakah ya atau tidak), maka tidak peduli terlalu banyak, dan Anda dapat mengabaikan masalah sampai jawabannya adalah jelas.

Satu- #!satunya tujuan adalah untuk meluncurkan skrip. Django memuat sumbernya sendiri dan menggunakannya. Tidak perlu memutuskan juru bahasa apa yang harus digunakan. Dengan cara ini, #!sebenarnya tidak masuk akal di sini.

Secara umum, jika itu adalah modul dan tidak dapat digunakan sebagai skrip, tidak perlu menggunakan #!. Di sisi lain, sumber modul sering mengandung if __name__ == '__main__': ...setidaknya beberapa pengujian fungsionalitas yang sepele. Kemudian #!masuk akal lagi.

Salah satu alasan bagus untuk menggunakan #!adalah ketika Anda menggunakan skrip Python 2 dan Python 3 - mereka harus ditafsirkan oleh versi Python yang berbeda. Dengan cara ini, Anda harus mengingat apa yang pythonharus digunakan ketika meluncurkan skrip secara manual (tanpa bagian #!dalam). Jika Anda memiliki campuran skrip-skrip seperti itu, sebaiknya gunakan bagian #!dalamnya, buat agar dapat dieksekusi, dan luncurkan sebagai skrip yang dapat dieksekusi (chmod ...).

Saat menggunakan MS-Windows, #!tidak masuk akal - sampai saat ini. Python 3.3 memperkenalkan Windows Python Launcher (py.exe dan pyw.exe) yang bertuliskan #!baris, mendeteksi versi Python yang diinstal, dan menggunakan versi Python yang benar atau dicari secara eksplisit. Karena ekstensi dapat dikaitkan dengan program, Anda bisa mendapatkan perilaku serupa di Windows seperti halnya menjalankan flag di sistem berbasis Unix.

semangat
sumber
3

Ketika saya menginstal Python 3.6.1 pada Windows 7 baru-baru ini, ia juga menginstal Python Launcher untuk Windows, yang seharusnya menangani garis shebang. Namun, saya menemukan bahwa Peluncur Python tidak melakukan ini: baris shebang diabaikan dan Python 2.7.13 selalu digunakan (kecuali saya mengeksekusi skrip menggunakan py -3).

Untuk memperbaikinya, saya harus mengedit kunci registri Windows HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Python.File\shell\open\command. Ini masih memiliki nilai

"C:\Python27\python.exe" "%1" %*

dari instalasi Python 2.7 saya sebelumnya. Saya mengubah nilai kunci registri ini menjadi

"C:\Windows\py.exe" "%1" %*

dan pemrosesan baris shebang Python Launcher berfungsi seperti dijelaskan di atas.

ETalbot
sumber
2

Jika Anda memiliki modul yang berbeda diinstal dan perlu menggunakan instalasi python tertentu, maka shebang tampaknya terbatas pada awalnya. Namun, Anda dapat melakukan trik seperti di bawah ini untuk memungkinkan shebang dipanggil terlebih dahulu sebagai skrip shell dan kemudian pilih python. Ini imo sangat fleksibel:

#!/bin/sh
#
# Choose the python we need. Explanation:
# a) '''\' translates to \ in shell, and starts a python multi-line string
# b) "" strings are treated as string concat by python, shell ignores them
# c) "true" command ignores its arguments
# c) exit before the ending ''' so the shell reads no further
# d) reset set docstrings to ignore the multiline comment code
#
"true" '''\'
PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3

if [ -x $PREFERRED_PYTHON ]; then
    echo Using preferred python $PREFERRED_PYTHON
    exec $PREFERRED_PYTHON "$0" "$@"
elif [ -x $ALTERNATIVE_PYTHON ]; then
    echo Using alternative python $ALTERNATIVE_PYTHON
    exec $ALTERNATIVE_PYTHON "$0" "$@"
else
    echo Using fallback python $FALLBACK_PYTHON
    exec python3 "$0" "$@"
fi
exit 127
'''

__doc__ = """What this file does"""
print(__doc__)
import platform
print(platform.python_version())

Atau lebih baik lagi, mungkin, untuk memfasilitasi penggunaan kembali kode di banyak skrip python:

#!/bin/bash
"true" '''\'; source $(cd $(dirname ${BASH_SOURCE[@]}) &>/dev/null && pwd)/select.sh; exec $CHOSEN_PYTHON "$0" "$@"; exit 127; '''

dan kemudian select.sh memiliki:

PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3

if [ -x $PREFERRED_PYTHON ]; then
    CHOSEN_PYTHON=$PREFERRED_PYTHON
elif [ -x $ALTERNATIVE_PYTHON ]; then
    CHOSEN_PYTHON=$ALTERNATIVE_PYTHON
else
    CHOSEN_PYTHON=$FALLBACK_PYTHON
fi
Neil McGill
sumber
1
Meskipun saya tidak yakin bahwa poliglot seperti ini adalah praktik yang baik secara umum, itu tentu saja pendekatan yang sangat menarik, dan mungkin jawaban yang paling fleksibel di sini.
Ryan Amos
1
Sangat keren. Saya tidak menyadari Anda bisa melakukan itu
user2233949
1

Jawab: Hanya jika Anda berencana menjadikannya skrip yang dapat dieksekusi command-line.

Inilah prosedurnya:

Mulailah dengan memverifikasi string shebang yang tepat untuk digunakan:

which python

Ambil output dari itu dan tambahkan (dengan shebang #!) Di baris pertama.

Di sistem saya merespons seperti ini:

$which python
/usr/bin/python

Jadi shebang Anda akan terlihat seperti:

#!/usr/bin/python

Setelah menyimpan, itu akan tetap berjalan seperti sebelumnya karena python akan melihat baris pertama sebagai komentar.

python filename.py

Untuk membuatnya menjadi perintah, salinlah untuk menjatuhkan ekstensi .py.

cp filename.py filename

Beri tahu sistem file bahwa ini akan dapat dieksekusi:

chmod +x filename

Untuk mengujinya, gunakan:

./filename

Praktik terbaik adalah memindahkannya di suatu tempat di $ PATH Anda sehingga yang perlu Anda ketikkan adalah nama file itu sendiri.

sudo cp filename /usr/sbin

Dengan begitu ia akan bekerja di mana saja (tanpa ./ sebelum nama file)

SDsolar
sumber
Saya ragu ini adalah praktik terbaik dan saya sangat merekomendasikan menggunakan solusi GlassGhost .
colidyre
Saya menemukan ini bermanfaat dan bekerja dengan baik untuk saya. ini dijelaskan dengan baik. Saya akan menghargai komentar yang menunjukkan mengapa ini bukan praktik terbaik. Saya ingin sekali belajar.
Charles Carriere
0

Absolute vs Logical Path:

Ini benar-benar sebuah pertanyaan tentang apakah jalur ke juru bahasa Python harus mutlak atau logis ( /usr/bin/env) sehubungan dengan portabilitas.

Mengetahui jawaban lain tentang hal ini dan situs Stack lain yang membahas masalah ini secara umum tanpa bukti pendukung, saya telah melakukan beberapa pengujian & analisis granular yang BENAR-BENAR untuk pertanyaan ini di unix.stackexchange.com . Daripada menempelkan jawaban itu di sini, saya akan mengarahkan mereka yang tertarik pada analisis komparatif untuk jawaban itu:

https://unix.stackexchange.com/a/566019/334294

Menjadi seorang Insinyur Linux, tujuan saya adalah selalu menyediakan host yang paling optimal dan dioptimalkan untuk klien pengembang saya, jadi masalah lingkungan Python adalah sesuatu yang saya benar-benar membutuhkan jawaban yang solid. Pandangan saya setelah pengujian adalah bahwa jalur logis dalam she-bang adalah yang lebih baik dari opsi (2).

F1Linux
sumber
-3

Gunakan dulu

which python

Ini akan memberikan output sebagai lokasi di mana penerjemah python saya (biner) hadir.

Output ini bisa berupa

/usr/bin/python

atau

/bin/python

Sekarang dengan tepat pilih garis shebang dan gunakan itu.

Untuk menggeneralisasi kita dapat menggunakan:

#!/usr/bin/env

atau

#!/bin/env
frp farhan
sumber
3
Ini kemungkinan besar tidak akan portabel untuk sistem lain. #!/usr/bin/envmembuat pilihan yang tepat untuk Anda.
fragmentedreality
Itu sebabnya Anda menggunakan whichperintah - itu akan mengembalikan string yang benar untuk sistem khusus Anda.
SDsolar
1
... dan kemudian setiap kali skrip akan dieksekusi pada komputer lain, Anda menjalankan which pythonlagi dan mengubah skrip jika output berbeda dari shebang saat ini
fragmentedreality
2
-1 Ini adalah solusi yang paling rapuh. Ini hanya dijamin benar untuk sistem di mana skrip python Anda ditulis. Gunakan #! / Usr / bin / env python3 untuk portabilitas
Myles Hollowed