Saya berada dalam sedikit situasi yang menarik di mana saya memiliki skrip Python yang secara teoritis dapat dijalankan oleh berbagai pengguna dengan berbagai lingkungan (dan PATH) dan pada berbagai sistem Linux. Saya ingin skrip ini dapat dieksekusi pada sebanyak mungkin dari ini tanpa batasan buatan. Berikut ini beberapa pengaturan yang diketahui:
- Python 2.6 adalah versi sistem Python, jadi python, python2, dan python2.6 semuanya ada di / usr / bin (dan setara).
- Python 2.6 adalah versi sistem Python, seperti di atas, tetapi Python 2.7 diinstal di sampingnya sebagai python2.7.
- Python 2.4 adalah versi sistem Python, yang tidak didukung skrip saya. Di / usr / bin kita memiliki python, python2, dan python2.4 yang setara, dan python2.5, yang didukung skrip.
Saya ingin menjalankan skrip python yang dapat dieksekusi yang sama pada ketiganya. Akan lebih baik jika mencoba menggunakan / usr/bin/python2.7 terlebih dahulu, jika ada, kemudian kembali ke /usr/bin/python2.6, kemudian kembali ke /usr/bin/python2.5, lalu cukup kesalahan jika tidak ada yang hadir. Saya tidak terlalu menutup telepon dengan menggunakan 2.x terbaru, asalkan bisa menemukan salah satu penerjemah yang tepat jika ada.
Kecenderungan pertama saya adalah mengubah garis shebang dari:
#!/usr/bin/python
untuk
#!/usr/bin/python2.[5-7]
karena ini berfungsi dengan baik di bash. Tetapi menjalankan skrip memberi:
/usr/bin/python2.[5-7]: bad interpreter: No such file or directory
Oke, jadi saya coba yang berikut ini, yang juga berfungsi di bash:
#!/bin/bash -c /usr/bin/python2.[5-7]
Tetapi sekali lagi, ini gagal dengan:
/bin/bash: - : invalid option
Oke, jelas saya hanya bisa menulis skrip shell terpisah yang menemukan penerjemah yang benar dan menjalankan skrip python menggunakan penerjemah apa pun yang ditemukannya. Saya hanya merasa kesulitan untuk mendistribusikan dua file di mana orang harus mencukupi selama itu dijalankan dengan interpreter python 2 yang paling up-to-date diinstal. Meminta orang untuk memohon penerjemah secara eksplisit (misalnya, $ python2.5 script.py
) bukanlah suatu pilihan. Mengandalkan PATH pengguna yang diatur dengan cara tertentu juga bukan pilihan.
Edit:
Pengecekan versi dalam skrip Python tidak akan berfungsi karena saya menggunakan pernyataan "with" yang ada pada Python 2.6 (dan dapat digunakan dalam 2.5 dengan from __future__ import with_statement
). Ini menyebabkan skrip gagal segera dengan SyntaxError pengguna-tidak ramah, dan mencegah saya dari memiliki kesempatan untuk memeriksa versi terlebih dahulu dan memancarkan kesalahan yang sesuai.
Contoh: (coba ini dengan penerjemah Python kurang dari 2,6)
#!/usr/bin/env python
import sys
print "You'll never see this!"
sys.exit()
with open('/dev/null', 'w') as out:
out.write('something')
import sys; sys.version_info()
untuk memeriksa apakah pengguna memiliki versi python yang diperlukan../script.py
) akan menyebabkan python2.4 untuk mengeksekusinya, yang akan menyebabkan kode Anda mendeteksi bahwa itu adalah versi yang salah (dan berhenti, mungkin). Tapi ada python2.5 yang sangat bagus yang bisa digunakan sebagai penerjemah!exec
jika demikian, cetak kesalahan.execve
). Argumennya adalah string literal, tidak ada globbing, tidak ada regexps. Itu dia. Bahkan jika arg pertama adalah "/ bin / bash" dan opsi kedua ("-c ...") opsi tersebut tidak diuraikan oleh shell. Mereka tidak ditangani ke bash executable, itulah sebabnya Anda mendapatkan kesalahan tersebut. Plus, shebang hanya berfungsi jika sudah di awal. Jadi Anda kurang beruntung di sini, saya takut (pendek naskah yang menemukan juru bahasa python dan memberinya sebuah dokumen DI SINI, yang terdengar seperti kekacauan yang mengerikan).Jawaban:
Saya bukan ahli, tapi saya percaya bahwa Anda tidak harus menentukan versi python yang tepat untuk digunakan dan meninggalkan pilihan itu ke sistem / pengguna.
Anda juga harus menggunakan itu alih-alih jalur hardcoding ke python dalam skrip:
atau
Hal ini direkomendasikan oleh Python doc di semua versi:
Dalam berbagai distribusi, Python dapat diinstal di tempat yang berbeda, jadi
env
akan mencarinya diPATH
. Itu harus tersedia di semua distribusi Linux utama dan dari apa yang saya lihat di FreeBSD.Skrip harus dijalankan dengan versi Python yang ada di PATH Anda dan yang dipilih oleh distribusi Anda *.
Jika skrip Anda kompatibel dengan semua versi Python kecuali 2.4, Anda harus mengeceknya jika dijalankan di Python 2.4 dan mencetak beberapa info dan keluar.
Lebih banyak untuk dibaca
env
.Catatan kaki
* Di Gentoo ada alat bernama
eselect
. Dengan menggunakannya, Anda dapat menetapkan versi default aplikasi yang berbeda (termasuk Python) sebagai default:sumber
Berdasarkan beberapa ide dari beberapa komentar, saya berhasil meretas sebuah hack yang benar-benar jelek yang tampaknya berhasil. Script menjadi skrip bash yang membungkus skrip Python dan meneruskannya ke juru bahasa Python melalui "dokumen di sini".
Pada awalnya:
Kode Python ada di sini. Kemudian di bagian paling akhir:
Saat pengguna menjalankan skrip, versi Python terbaru antara 2.5 dan 2.7 digunakan untuk menafsirkan sisa skrip sebagai dokumen di sini.
Penjelasan tentang beberapa shenanigans:
Hal-hal triple-quote yang saya tambahkan juga memungkinkan skrip yang sama ini diimpor sebagai modul Python (yang saya gunakan untuk tujuan pengujian). Ketika diimpor oleh Python, semua yang ada di antara triple-single-quote pertama dan kedua ditafsirkan sebagai string tingkat modul, dan triple-single-quote ketiga dikomentari. Sisanya adalah Python biasa.
Ketika dijalankan secara langsung (sebagai skrip bash sekarang), dua tanda kutip tunggal menjadi string kosong, dan tanda kutip tunggal ketiga membentuk string lain dengan tanda kutip tunggal keempat, yang hanya berisi tanda titik dua. String ini ditafsirkan oleh Bash sebagai no-op. Semua yang lain adalah sintaks Bash untuk globbing binari Python di / usr / bin, memilih yang terakhir, dan menjalankan exec, melewati sisa file sebagai dokumen di sini. Dokumen di sini dimulai dengan kutipan tiga-tunggal Python yang hanya berisi tanda hash / pound / octothorpe. Sisa skrip kemudian ditafsirkan sebagai normal sampai baris yang membaca '# EOF' mengakhiri dokumen di sini.
Saya merasa ini sesat, jadi saya berharap seseorang memiliki solusi yang lebih baik.
sumber
# ft=python
.Garis shebang hanya dapat menentukan jalur tetap ke juru bahasa. Ada
#!/usr/bin/env
trik untuk mencari penerjemah diPATH
tetapi itu saja. Jika Anda menginginkan lebih banyak kecanggihan, Anda perlu menulis beberapa kode shell wrapper.Solusi yang paling jelas adalah menulis skrip wrapper. Panggil skrip python
foo.real
dan buat skrip wrapperfoo
:Jika Anda ingin meletakkan semuanya dalam satu file, Anda sering dapat menjadikannya polyglot yang dimulai dengan
#!/bin/sh
baris (jadi akan dieksekusi oleh shell) tetapi juga merupakan skrip yang valid dalam bahasa lain. Bergantung pada bahasanya, poliglot mungkin tidak mungkin (jika#!
menyebabkan kesalahan sintaksis, misalnya). Dalam Python, itu tidak terlalu sulit.(Seluruh teks antara
'''
dan'''
merupakan string Python di tingkat atas, yang tidak memiliki efek. Untuk shell, baris kedua adalah''':'
yang setelah pengupasan tanda kutip adalah perintah no-op:
.)sumber
# EOF
pada akhir seperti pada jawaban ini . Pendekatan Anda pada dasarnya sama dengan yang diuraikan di sini .Karena persyaratan Anda menyatakan daftar binari yang diketahui, Anda bisa melakukannya dengan Python dengan yang berikut ini. Itu tidak akan berfungsi melewati satu digit minor / versi utama dari Python tapi saya tidak melihat itu terjadi dalam waktu dekat.
Menjalankan versi tertinggi yang terletak di disk dari daftar ular piton berversi yang diperintahkan dan bertambah, jika versi yang ditandai pada biner lebih tinggi daripada versi eksekusi python saat ini. "Daftar peningkatan versi yang dipesan" menjadi bit penting untuk kode ini.
Permintaan maaf untuk ular piton saya yang gatal
sumber
from __future__ import with_statement
, yang harus menjadi hal pertama dalam skrip Python. Saya kira Anda tidak tahu cara melakukan tindakan itu ketika memulai juru bahasa baru?with
seperti impor biasa ?. Apakahif mypy == 25: from __future__ import with_statement
pekerjaan tambahan tepat sebelum 'barang normal'? Anda mungkin tidak memerlukan if, jika Anda tidak mendukung 2.4.Anda dapat menulis skrip bash kecil yang memeriksa executable phython yang tersedia dan menyebutnya dengan skrip sebagai parameter. Anda kemudian dapat membuat skrip ini sebagai target garis shebang:
Dan skrip ini cukup (setelah pencarian):
Saya tidak yakin apakah kernel akan menerima tipuan skrip ini, tetapi saya memeriksa dan berfungsi.
Edit 1
Untuk menjadikan ketidakpahaman yang memalukan ini, proposal yang bagus akhirnya:
Dimungkinkan untuk menggabungkan kedua skrip dalam satu file. Anda cukup menulis skrip python sebagai dokumen di sini di skrip bash (jika Anda mengubah skrip python, Anda hanya perlu menyalin skrip tersebut lagi). Entah Anda membuat file sementara dalam eg / tmp atau (jika python mendukungnya, saya tidak tahu) Anda memberikan skrip sebagai input ke penerjemah:
sumber
$(ls /usr/bin/python?.? | tail -n1 )
tapi saya tidak berhasil menggunakan ini secara cerdik dalam shebang.