ฉันจะใช้ตัวแปรสภาพแวดล้อมใน shebang ของฉันได้อย่างไร


34

ฉันมีสคริปต์ Python ที่ต้องรันด้วยการติดตั้ง python มีวิธีในการสร้าง shebang ให้มันทำงานด้วย$FOO/bar/MyCustomPythonหรือไม่?

คำตอบ:


29

สาย shebang มี จำกัด มาก ภายใต้ตัวแปร unix จำนวนมาก (รวมถึง Linux) คุณสามารถมีได้สองคำเท่านั้น: คำสั่งและอาร์กิวเมนต์เดียว นอกจากนี้ยังมักจะมีข้อจำกัดความยาว

วิธีแก้ปัญหาทั่วไปคือการเขียนเปลือกห่อเล็ก ๆ ชื่อสคริปต์ Python foo.pyและวางสคริปต์เปลือกติดกับและเรียกมันว่าfoo.py fooวิธีนี้ไม่จำเป็นต้องมีส่วนหัวใด ๆ ในสคริปต์ Python

#!/bin/sh
exec "$FOO/bar/MyCustomPython" "$0.py" "$@"

อีกวิธีหนึ่งที่น่าดึงดูดคือการเขียนสคริปต์ตัวห่อหุ้มแบบเดียวกับที่กล่าวไว้ข้างต้นและวางไว้#!/path/to/wrapper/scriptในแนวชีทบนสคริปต์ Python อย่างไรก็ตามยูนิเซฟส่วนใหญ่ไม่รองรับการผูกมัดของสคริปต์ shebang ดังนั้นสิ่งนี้จะไม่ทำงาน

หากMyCustomPythonอยู่ใน$PATHนั้นคุณสามารถใช้envเพื่อค้นหา:

#!/usr/bin/env MyCustomPython
import 

อีกวิธีหนึ่งคือการจัดเรียงสคริปต์ให้เป็นทั้งเชลล์สคริปต์ที่ถูกต้อง (ซึ่งโหลด Python ล่ามที่ถูกต้องด้วยตัวเอง) และสคริปต์ที่ถูกต้องในภาษาเป้าหมาย (นี่คือ Python) สิ่งนี้ต้องการให้คุณหาวิธีเขียนสคริปต์สองภาษาดังกล่าวสำหรับภาษาเป้าหมายของคุณ ใน Perl if $running_under_some_shellนี้เป็นที่รู้จักกัน

#!/bin/sh
eval 'exec "$FOO/bar/MyCustomPerl" -wS $0 ${1+"$@"}'
    if $running_under_some_shell;
use 

ต่อไปนี้เป็นวิธีหนึ่งในการสร้างเอฟเฟกต์เดียวกันใน Python ในเชลล์"true"คือtrueยูทิลิตีซึ่งจะละเว้นอาร์กิวเมนต์ (สองสตริงอักขระเดี่ยว:และ') และส่งคืนค่าจริง ใน Python "true"เป็นสตริงที่เป็นจริงเมื่อตีความว่าเป็นบูลีนดังนั้นนี่คือifคำสั่งที่เป็นจริงเสมอและดำเนินการตามตัวอักษรสตริง

#!/bin/sh
if "true" : '''\'
then
exec "$FOO/bar/MyCustomPython" "$0" "$@"
exit 127
fi
'''
import 

รหัส Rosetta มีสคริปต์สองภาษาในหลายภาษา


1
@Chris: ทุกอย่างอยู่ในคำพูดเดียว โปรดอธิบาย ...
Stéphane Gimenez

1
คุณเป็นพ่อมดเลือด ... นี่เยี่ยมมาก ฉันใช้สิ่งนี้เพื่อแก้ไขPYTHONPATHตัวแปร env เพื่อโหลดโมดูลจากตำแหน่งที่ไม่ได้มาตรฐานสำหรับสคริปต์ CGI บนระบบที่ฉันไม่สามารถเข้าถึงรูตได้ ช่วยชีวิต ขอบคุณอีกครั้ง.
wspurgin

12

เส้น Shebang ไม่ผ่านการขยายตัวของตัวแปรดังนั้นคุณจึงไม่สามารถใช้งานได้$FOO/MyCustomPythonเพราะมันจะค้นหาไฟล์ปฏิบัติการที่เรียกว่า dollar-FOO -...

อีกทางเลือกหนึ่งคือให้ shebang ของคุณชี้ไปที่เชลล์สคริปต์ในฐานะล่ามและเชลล์สคริปต์นี้สามารถใช้ตัวแปรสภาพแวดล้อมเพื่อค้นหาที่ถูกต้องและดำเนินการได้

ตัวอย่าง: สร้างmypython.shสคริปต์ใน/usr/local/bin(หรือไดเรกทอรีอื่น ๆ ของคุณ$PATH) ด้วยเนื้อหาดังต่อไปนี้:

#! /bin/sh
PYTHON="$FOO/bar/MyCustomPython"
exec "$PYTHON" "$@"

จากนั้นคุณสามารถใช้บรรทัด shebang นี้เพื่อให้สคริปต์ Python ดำเนินการผ่านMyCustomPythonทางmypython.sh:

#!/usr/bin/env mypython.sh

6
ใช้$pythonไม่ใช่$PYTHONตามแบบแผนเราใช้ประโยชน์จากตัวแปรสภาพแวดล้อม (PAGER, EDITOR, SHELL ... $PYTHONในสคริปต์ของคุณไม่ใช่ตัวแปรสภาพแวดล้อม) และตัวแปรเชลล์ภายใน (BASH_VERSION, RANDOM, ... ) ชื่อตัวแปรอื่น ๆ ทั้งหมดควรมีตัวอักษรพิมพ์เล็กอย่างน้อยหนึ่งตัว อนุสัญญานี้หลีกเลี่ยงการแก้ไขตัวแปรสภาพแวดล้อมและภายในโดยไม่ตั้งใจ นอกจากนี้อย่าใช้ส่วนขยายสำหรับสคริปต์ของคุณ สคริปต์กำหนดคำสั่งใหม่ที่คุณสามารถเรียกใช้ได้และโดยทั่วไปคำสั่งจะไม่ได้รับส่วนขยาย
Chris Down

4

คุณสามารถใช้พา ธ สัมบูรณ์ไปยังการติดตั้งหลามแบบกำหนดเองหรือคุณสามารถใส่มันลงใน$PATHและใช้งาน#!/usr/bin/env [command]ได้ มิฉะนั้นให้เขียน wrapper สำหรับมันและใช้execเพื่อแทนที่อิมเมจกระบวนการดังตัวอย่าง:

#!/bin/bash
exec "$ENV/python" "$@"

3

ขั้นแรกให้พิจารณาว่ารุ่น Python ของคุณแตกต่างจาก Python มาตรฐานที่ติดตั้งไว้แล้วอย่างไร (ตัวอย่างเช่นโมดูลเพิ่มเติม) จากนั้นเมื่อเริ่มต้นโปรแกรม 'switch' วิธีที่ Python เรียกว่า:

#!/usr/bin/python
import os
import sys
try:
    import MyCustomModule
except ImportError:
    # only need to use expandvar if you know the string below has an envvar
    custprog = os.path.expandvar("$FOO/bar/MyCustomPython")
    os.execv(custprog, sys.argv) # call alternate python with the same arguments
    raise SystemExit('could not call %s' % custprog)
# if we get here, then we have the correct python interpreter

สิ่งนี้จะทำให้โปรแกรมสามารถเรียกใช้งานได้โดยอินสแตนซ์อื่นของ Python ฉันทำสิ่งที่คล้ายกันสำหรับอินสแตนซ์ที่มีไลบรารี sql ในตัวที่ไม่สามารถนำเข้าเป็นโมดูลในหลามของระบบ


0

หากคุณสามารถแทนที่$FOOใน$FOO/bar/MyCustomPythonที่มีตัวเลือกเส้นทางคอนกรีตคุณสามารถบอกenvบรรทัด shebang ที่จะมองขึ้นรุ่นหลามของคุณกำหนดเองโดยการตั้งค่าได้โดยตรงที่กำหนดเองPATHในนั้น

#!/usr/bin/env PATH="/path1/to/MyCustomPython:/path2/to/MyCustomPython" python

แก้ไข : ดูเหมือนว่าจะทำงานโดยไม่มีเครื่องหมายคำพูดล้อมรอบการกำหนดค่า PATH:

#!/usr/bin/env PATH=/path1/to/MyCustomPython:/path2/to/MyCustomPython python

5
ระวังว่ามันใช้ไม่ได้กับ unix ทุกรุ่น (เช่นไม่ใช่ใน Linux) และคุณกำลังลบไดเรกทอรีที่มีอยู่ทั้งหมดออกจากเส้นทางซึ่งมีแนวโน้มที่จะทำให้เกิดปัญหาตามมา
Gilles 'หยุดความชั่วร้าย'

1
ขยายตัวได้ดีขึ้นPATHเช่นนี้:PATH=$PATH:/path/to/whatever...
Bengt
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.