Bagaimana / usr / bin / env tahu program mana yang digunakan?

62

Ketika saya menggunakan shebang #!/usr/bin/env pythonuntuk menjalankan skrip, bagaimana sistem tahu mana yang pythonharus digunakan? jika saya mencari pythonpath bin dalam variabel lingkungan saya tidak menemukan apa pun.

env | grep -i python
tMC
sumber
6
oh saya pikir saya sudah menemukannya - hanya mencari $ PATH Anda untuk 'python'
tMC
Saya juga bertanya-tanya tentang hal itu. Dan mengapa / usr / bin / env? sebagai lawan dari / bin / env atau env, apakah itu hanya mendapatkan daftar path dari env?
Faheem Mitha
Hanya 'env' tidak akan bekerja karena itu harus jalur penuh. Program 'env' biasanya ditemukan di / user / bin / env. Pada beberapa distro mungkin juga ditemukan sebagai / bin / env, tetapi lebih aman untuk pergi dengan / usr / bin / env.
rettop

Jawaban:

55

Shebang mengharapkan path lengkap ke interpreter untuk digunakan sehingga sintaks berikut akan salah:

#!python

Menyetel path lengkap seperti ini mungkin berhasil:

#!/usr/local/bin/python

tapi akan non portable seperti python mungkin dipasang di /bin, /opt/python/bin, atau di mana pun lokasi lain.

Menggunakan env

#!/usr/bin/env python

adalah metode yang memungkinkan cara portabel untuk menentukan ke OS path lengkap setara dengan yang mana pythonpertama kali terletak di PATH.

Jlliagre
sumber
57

Garis shebang (dari "bang tajam", yaitu #!) diproses oleh kernel. Kernel tidak ingin tahu tentang variabel lingkungan seperti PATH. Jadi nama pada baris shebang harus menjadi jalur absolut ke executable. Anda juga dapat menentukan argumen tambahan untuk diteruskan ke yang dapat dieksekusi sebelum nama skrip (dengan pembatasan yang bergantung pada sistem saya tidak akan masuk ke sini). Misalnya, untuk skrip Python, Anda bisa menentukan

#!/usr/bin/python

pada baris pertama, dan ketika Anda menjalankan skrip, kernel sebenarnya akan mengeksekusi /usr/bin/python /path/to/script. Tapi itu tidak nyaman: Anda perlu menentukan path lengkap dari perintah. Bagaimana jika Anda memiliki pythondi /usr/binbeberapa mesin dan /usr/local/binpada orang lain? Atau Anda ingin mengatur Anda PATHuntuk /home/joe/opt/python-2.5/binsehingga untuk menggunakan versi tertentu dari Python? Karena kernel tidak akan melakukan PATHpencarian untuk Anda, idenya adalah membuat kernel menjalankan perintah yang pada gilirannya mencari penerjemah yang diinginkan di PATH:

#!/fixed/path/to/path-lookup-command python

Itu path-lookup-commandharus mengambil nama yang dapat dieksekusi sebagai argumen dan mencarinya PATHdan menjalankannya: kernel akan berjalan /fixed/path/to/path-lookup-command python /path/to/script. Ketika itu terjadi, envperintah tidak hanya itu. Tujuan utamanya adalah untuk menjalankan perintah dengan lingkungan yang berbeda, tetapi karena mencari nama perintah $PATH, itu sempurna untuk tujuan kita di sini.

Meskipun ini tidak secara resmi dijamin, sistem Unix bersejarah disediakan envdi /usr/bin, dan sistem modern telah disimpan lokasi itu justru karena meluasnya penggunaan #!/usr/bin/env. Jadi, dalam praktiknya, cara untuk menentukan bahwa skrip harus dijalankan oleh interpreter Python favorit pengguna adalah

#!/usr/bin/env python
Gilles 'SANGAT berhenti menjadi jahat'
sumber
2
yang mana yang disukai antara envdan which? karena itu juga akan mendapatkan executable paling memenuhi syarat dari lingkungan PATH saya.
Nikhil Mulley
8
@NikhilMulley whichmenemukan executable dan mencetak path-nya. envmenemukan program yang ditentukan oleh argumen pertama dan menjalankannya, meneruskannya dengan argumen yang tersisa.
Kevin
3
jadi apakah itu envversi eval whichdasarnya.
Nikhil Mulley
7

Benar, jadi jalankan:

env | grep PATH

$ PATH Anda adalah daftar direktori. Unix akan memeriksa daftar direktori, secara berurutan, hingga ia menemukan "python".

Anda dapat melihat direktori mana yang ditemukannya dengan perintah 'mana':

which python
Dan Rue
sumber
Menariknya, saya melihat perbedaan dalam python sys.pathantara env $ env python3 ( ['', '/home/user/test', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/home/user/.local/lib/python3.4/site-packages', '/usr/lib/python3.4/site-packages', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages']) dan ./env/bin/python3 (['', '/home/user/test', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/home/user/test/env3/lib/python3.4/site-packages']) yang diaktifkan .
ThorSummoner