Sepertinya saya suka menjalankan file yang sama tanpa garis itu.
Sepertinya saya suka menjalankan file yang sama tanpa garis itu.
Jawaban:
Jika Anda memiliki beberapa versi Python yang diinstal, /usr/bin/env
akan memastikan penerjemah 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, file yang dapat dieksekusi yang dimaksudkan untuk ditafsirkan dapat menunjukkan penerjemah apa yang harus digunakan dengan memiliki #!
di awal baris pertama, diikuti oleh penerjemah (dan bendera apa pun yang mungkin diperlukan).
Jika Anda berbicara tentang platform lain, tentu saja, aturan ini tidak berlaku (tetapi "garis shebang" tidak ada salahnya, dan akan membantu jika Anda pernah menyalin skrip itu ke platform dengan basis Unix, seperti Linux, Mac , dll).
chmod +x myscript.py
) dan kemudian menjalankannya secara langsung ./myscript.py
:, bukan hanya python myscript.py
.
env
memberikan fleksibilitas maksimum dalam hal pengguna dapat memilih juru bahasa untuk digunakan dengan mengubah PATH. Seringkali fleksibilitas ini tidak diperlukan meskipun dan downside adalah bahwa linux misalnya tidak dapat menggunakan nama skrip untuk nama proses ps
dan kembali ke "python". Ketika mengemas aplikasi python untuk distro misalnya saya akan menyarankan untuk tidak menggunakan env
.
py
peluncur dapat menggunakan garis shebang di Windows. Ini termasuk dalam Python 3.3 atau dapat diinstal secara independen .
/usr/bin/env: Key has expired
setelah berjam-jam.
Itu disebut garis shebang . Sebagaimana dijelaskan oleh entri Wikipedia :
Dalam komputasi, shebang (juga disebut hashbang, hashpling, pound bang, atau crunchbang) mengacu pada karakter "#!" ketika mereka adalah dua karakter pertama dalam arahan juru bahasa sebagai baris pertama dari file teks. Dalam sistem operasi mirip Unix, program loader mengambil keberadaan dua karakter ini sebagai indikasi bahwa file tersebut adalah skrip, dan mencoba untuk mengeksekusi skrip itu menggunakan interpreter yang ditentukan oleh sisa baris pertama dalam file.
Lihat juga entri FAQ Unix .
Bahkan pada Windows, di mana garis shebang tidak menentukan penerjemah yang akan dijalankan, Anda dapat meneruskan opsi ke juru bahasa dengan menentukannya pada garis shebang. Saya merasa berguna untuk menjaga garis shebang generik dalam skrip satu kali (seperti yang saya tulis saat menjawab pertanyaan pada SO), jadi saya dapat dengan cepat mengujinya pada Windows dan ArchLinux .
The utilitas env memungkinkan Anda untuk memanggil perintah pada jalan:
Argumen yang tersisa pertama menentukan nama program yang akan dipanggil; itu dicari sesuai dengan
PATH
variabel lingkungan. Argumen yang tersisa dilewatkan sebagai argumen untuk program itu.
Memperluas sedikit jawaban yang lain, inilah sedikit contoh bagaimana skrip baris perintah Anda bisa mendapat masalah dengan penggunaan /usr/bin/env
garis shebang yang tidak hati-hati :
$ /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 Python 3 juga memberikan python3
nama:
$ cat my_script.py
#!/usr/bin/env python3
import json
print("hello, json")
which python
kembali /usr/bin/python
, jalur direktori lokal bisa sulit kode: #!/usr/bin/python
. Tapi itu kurang fleksibel daripada #!/usr/bin/env python
yang memiliki aplikasi global.
Untuk menjalankan skrip python, kita perlu memberi tahu shell tiga hal:
Shebang #!
mencapai (1.). Shebang dimulai dengan a #
karena #
karakter adalah penanda komentar dalam banyak bahasa scripting. Oleh karena itu, isi garis shebang secara otomatis diabaikan oleh penerjemah.
The env
perintah menyelesaikan (2.) dan (3). Mengutip "grawity,"
Penggunaan umum dari
env
perintah ini adalah untuk meluncurkan penerjemah, dengan memanfaatkan fakta bahwa env akan mencari $ PATH untuk perintah yang diperintahkan untuk diluncurkan. Karena garis shebang membutuhkan jalur absolut yang harus ditentukan, dan karena lokasi berbagai penafsir (perl, bash, python) dapat sangat bervariasi, itu biasa digunakan:
#!/usr/bin/env perl
alih-alih mencoba menebak apakah itu adalah / bin / perl, / usr / bin / perl, / usr / local / bin / perl, / usr / local / pkg / perl, / fileserver / usr / bin / perl, atau / home / MrDaniel / usr / bin / perl pada sistem pengguna ...Di sisi lain, env hampir selalu di / usr / bin / env. (Kecuali dalam kasus-kasus ketika tidak; beberapa sistem mungkin menggunakan / bin / env, tetapi itu adalah kesempatan yang cukup langka dan hanya terjadi pada sistem non-Linux.)
Mungkin pertanyaan Anda dalam pengertian ini:
Jika Anda ingin menggunakan: $python myscript.py
Anda tidak perlu saluran itu sama sekali. Sistem akan memanggil python dan kemudian python interpreter akan menjalankan skrip Anda.
Tetapi jika Anda berniat untuk menggunakan: $./myscript.py
Memanggilnya langsung seperti program normal atau skrip bash, Anda perlu menulis baris itu untuk menentukan sistem yang digunakan program untuk menjalankannya, (dan juga membuatnya dapat dieksekusi dengan chmod 755
)
The exec
system call dari kernel Linux mengerti shebangs ( #!
) native
Ketika Anda melakukannya di bash:
./something
di Linux, ini memanggil exec
system 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 exec
panggilan lain dengan path /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 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 exec
panggilan sistem akan menggunakan penangan yang berbeda. Handler bawaan 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 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: Bagaimana kernel menjalankan file biner yang dapat dieksekusi berjalan di linux?
Akhirnya, Anda dapat menambahkan penangan shebang Anda sendiri dengan binfmt_misc
mekanismenya. Misalnya, Anda dapat menambahkan penangan khusus untuk .jar
file . 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". macOS dan FreeBSD juga tampaknya mengimplementasikannya.
PATH
motivasi pencarian
Kemungkinan, satu motivasi besar untuk keberadaan shebang adalah kenyataan bahwa di Linux, kita sering ingin menjalankan perintah PATH
hanya dari :
basename-of-command
dari pada:
/full/path/to/basename-of-command
Tapi kemudian, tanpa mekanisme shebang, bagaimana Linux tahu cara meluncurkan setiap jenis file?
Hardcoding ekstensi dalam perintah:
basename-of-command.py
atau menerapkan pencarian PATH pada setiap penerjemah:
python basename-of-command
akan menjadi suatu kemungkinan, tetapi ini memiliki masalah besar bahwa semuanya rusak jika kita pernah memutuskan untuk mengubah perintah ke bahasa lain.
Shebangs memecahkan masalah ini dengan indah.
Secara teknis, dalam Python, ini hanya sebuah baris komentar.
Baris ini hanya digunakan jika Anda menjalankan skrip py dari shell (dari baris perintah). Ini dikenal sebagai " Shebang !" , dan digunakan dalam berbagai situasi, tidak hanya dengan skrip Python.
Di sini, ia memerintahkan shell untuk memulai versi Python tertentu (untuk menjaga sisa file.
py.exe
. Ini adalah bagian dari instalasi Python standar.
Alasan utama untuk melakukan ini adalah untuk membuat skrip portable di seluruh lingkungan sistem operasi.
Misalnya di bawah mingw, skrip python gunakan:
#!/c/python3k/python
dan di bawah distribusi GNU / Linux itu adalah:
#!/usr/local/bin/python
atau
#!/usr/bin/python
dan di bawah sistem Unix sw / hw komersial terbaik semua (OS / X), itu adalah:
#!/Applications/MacPython 2.5/python
atau di FreeBSD:
#!/usr/local/bin/python
Namun semua perbedaan ini dapat membuat skrip portable di semua dengan menggunakan:
#!/usr/bin/env python
/usr/bin/python
. Di Linux, Python yang diinstal oleh sistem juga hampir pasti /usr/bin/python
(saya belum pernah melihat yang lain dan itu tidak masuk akal). Perhatikan bahwa mungkin ada sistem yang tidak memiliki /usr/bin/env
.
python
tidak terlalu portabel, itu adalah penerjemah default Python. Arch Linux default ke Python 3 untuk waktu yang lama dan mungkin distribusi memikirkannya juga karena Python 2 hanya didukung hingga 2020.
Mungkin masuk akal untuk menekankan satu hal yang paling banyak terlewatkan, yang dapat mencegah pemahaman langsung. Saat Anda mengetikkan python
terminal, biasanya Anda tidak menyediakan jalur lengkap. Sebagai gantinya, executable terlihat dalam PATH
variabel lingkungan. Pada gilirannya, ketika Anda ingin menjalankan program Python secara langsung,, /path/to/app.py
seseorang harus memberi tahu shell apa yang harus digunakan juru bahasa (melalui hashbang , apa yang dijelaskan oleh kontributor lain di atas).
Hashbang mengharapkan jalan penuh ke penerjemah. Jadi untuk menjalankan program Python Anda secara langsung, Anda harus memberikan path lengkap ke Python binary yang sangat bervariasi, terutama mengingat penggunaan virtualenv . Untuk mengatasi portabilitas, trik /usr/bin/env
yang digunakan. Yang terakhir ini awalnya dimaksudkan untuk mengubah lingkungan di tempat dan menjalankan perintah di dalamnya. Ketika tidak ada perubahan disediakan itu menjalankan perintah di lingkungan saat ini, yang secara efektif menghasilkan PATH
pencarian yang sama yang melakukan trik.
Ini adalah konvensi shell yang memberi tahu shell program mana yang dapat menjalankan skrip.
#! / usr / bin / env python
menyelesaikan ke jalur ke biner Python.
Ini direkomendasikan, diusulkan dalam dokumentasi:
2.2.2. Skrip Python yang Dapat Dieksekusi
Pada sistem BSD'ish Unix, skrip Python dapat dibuat langsung dapat dieksekusi, seperti skrip shell, dengan meletakkan baris
#! /usr/bin/env python3.2
dari http://docs.python.org/py3k/tutorial/interpreter.html#executable-python-scripts
Anda dapat mencoba masalah ini menggunakan virtualenv
Inilah test.py
#! /usr/bin/env python
import sys
print(sys.version)
Buat lingkungan virtual
virtualenv test2.6 -p /usr/bin/python2.6
virtualenv test2.7 -p /usr/bin/python2.7
aktifkan masing-masing lingkungan lalu periksa perbedaannya
echo $PATH
./test.py
Itu hanya menentukan penerjemah apa yang ingin Anda gunakan. Untuk memahami hal ini, buat file melalui terminal dengan melakukan touch test.py
, lalu ketikkan ke file itu sebagai berikut:
#!/usr/bin/env python3
print "test"
dan lakukan chmod +x test.py
untuk membuat skrip Anda dapat dieksekusi. Setelah ini ketika Anda melakukannya, ./test.py
Anda akan mendapatkan pesan kesalahan:
File "./test.py", line 2
print "test"
^
SyntaxError: Missing parentheses in call to 'print'
karena python3 tidak mendukung operator cetak.
Sekarang, lanjutkan dan ubah baris pertama kode Anda ke:
#!/usr/bin/env python2
dan itu akan berhasil, mencetak test
ke stdout, karena python2 mendukung operator cetak. Jadi, sekarang Anda telah belajar cara beralih antar penerjemah skrip.
Sepertinya saya suka menjalankan file yang sama tanpa garis itu.
Jika demikian, maka mungkin Anda menjalankan program Python di Windows? Windows tidak menggunakan baris itu — sebaliknya, ia menggunakan ekstensi nama file untuk menjalankan program yang terkait dengan ekstensi file.
Namun pada tahun 2011, "peluncur Python" dikembangkan yang (sampai taraf tertentu) meniru perilaku Linux ini untuk Windows. Ini terbatas hanya untuk memilih interpreter Python mana yang dijalankan - misalnya untuk memilih antara Python 2 dan Python 3 pada sistem di mana keduanya diinstal. Peluncur secara opsional diinstal sebagai py.exe
oleh instalasi Python, dan dapat dikaitkan dengan .py
file sehingga peluncur akan memeriksa baris itu dan pada gilirannya meluncurkan versi interpreter Python yang ditentukan.
$ python myscript.py
.
Ini dimaksudkan sebagai lebih banyak informasi historis daripada jawaban "nyata".
Ingatlah bahwa di masa lalu Anda memiliki BANYAK sistem operasi unix like yang perancangnya semua memiliki gagasan sendiri tentang di mana harus meletakkan barang, dan kadang-kadang tidak termasuk Python, Perl, Bash, atau banyak hal GNU / Open Source lainnya sama sekali .
Ini bahkan berlaku untuk distribusi Linux yang berbeda. Di Linux - pra-FHS [1] -Anda mungkin memiliki python di / usr / bin / atau / usr / local / bin /. Atau mungkin belum diinstal, jadi Anda membuat sendiri dan memasukkannya ke ~ / bin
Solaris adalah yang terburuk yang pernah saya kerjakan, sebagian sebagai transisi dari Berkeley Unix ke Sistem V. Anda bisa berakhir dengan hal-hal di / usr /, / usr / local /, / usr / ucb, / opt / dll. Ini bisa membuat untuk beberapa benar-benar jalur yang panjang. Saya memiliki kenangan tentang hal-hal dari Sunfreeware.com menginstal setiap paket di direktori itu sendiri, tetapi saya tidak dapat mengingat apakah itu menyinkronkan binari ke / usr / bin atau tidak.
Oh, dan terkadang / usr / bin berada di server NFS [2].
Jadi env
utilitas dikembangkan untuk mengatasi ini.
Kemudian Anda bisa menulis #!/bin/env interpreter
dan selama jalannya benar, hal-hal yang wajar memiliki peluang untuk berjalan. Tentu saja, masuk akal berarti (untuk Python dan Perl) bahwa Anda juga telah menetapkan variabel lingkungan yang sesuai. Untuk bash / ksh / zsh itu hanya berfungsi.
Ini penting karena orang-orang sedang membagikan skrip shell (seperti perl dan python) dan jika Anda ingin mengode / usr / bin / python di workstation Red Hat Linux Anda, itu akan sangat buruk pada SGI ... well, tidak , Saya pikir IRIX meletakkan python di tempat yang tepat. Tetapi pada stasiun Sparc mungkin tidak berjalan sama sekali.
Saya merindukan stasiun sparc saya. Tapi tidak banyak. Ok, sekarang Anda membuat saya berkeliling di E-Bay. Bajingan.
[1] Standar Hirarki sistem file. https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
[2] Ya, dan terkadang orang masih melakukan hal-hal seperti itu. Dan tidak, saya tidak memakai lobak ATAU bawang di ikat pinggang saya.
Jika Anda menjalankan skrip Anda di lingkungan virtual, katakanlah venv
, mengeksekusi which python
sambil bekerja venv
akan menampilkan jalur ke juru bahasa Python:
~/Envs/venv/bin/python
Perhatikan bahwa nama lingkungan virtual tertanam di jalur ke penerjemah Python. Oleh karena itu, meng-hardcoding jalur ini dalam skrip Anda akan menyebabkan dua masalah:
Oleh karena itu, untuk menambah jawaban Jonathan , shebang yang ideal adalah #!/usr/bin/env python
, tidak hanya untuk portabilitas di seluruh OS tetapi untuk portabilitas di lingkungan virtual juga!
Mempertimbangkan masalah portabilitas di antara python2
dan python3
, Anda harus selalu menentukan versi mana pun kecuali jika program Anda kompatibel dengan keduanya.
Beberapa distribusi pengiriman python
terhubung python3
untuk sementara waktu sekarang - jangan bergantung pada python
keberadaan python2
.
Ini ditekankan oleh PEP 394 :
Untuk mentolerir perbedaan antar platform, semua kode baru yang perlu memanggil juru bahasa Python tidak boleh menentukan python, tetapi lebih baik menentukan python2 atau python3 (atau versi python2.x dan python3.x yang lebih spesifik; lihat Migration Notes ) . Perbedaan ini harus dibuat di shebangs, ketika memohon dari skrip shell, ketika memohon melalui system () panggilan, atau ketika memohon dalam konteks lain.
Ini memungkinkan Anda untuk memilih executable yang ingin Anda gunakan; yang sangat berguna jika mungkin Anda memiliki beberapa pemasangan python, dan modul yang berbeda di masing-masing dan ingin memilih. misalnya
#!/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 $ALTERNATIVE_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())
ini memberitahu script di mana direktori python!
#! /usr/bin/env python
#!/usr/bin/env python
di bagian atas.