Come posso usare le variabili d'ambiente nel mio shebang?


34

Ho uno script Python che deve essere eseguito con una particolare installazione di Python. C'è un modo per fabbricare un shebang in modo che corra $FOO/bar/MyCustomPython?

Risposte:


29

La linea Shebang è molto limitata. In molte varianti unix (incluso Linux), puoi avere solo due parole: un comando e un singolo argomento. C'è anche spesso una limitazione di lunghezza.

La soluzione generale è scrivere un piccolo involucro di shell. Assegna un nome allo script Python foo.py, avvicina lo script shell foo.pye chiamalo foo. Questo approccio non richiede alcuna intestazione particolare sullo script Python.

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

Un altro approccio allettante è scrivere uno script wrapper come quello sopra e metterlo #!/path/to/wrapper/scriptcome linea shebang nello script Python. Tuttavia, molti unice non supportano il concatenamento di script shebang, quindi non funzionerà.

Se MyCustomPythonfosse nel $PATH, puoi usare envper cercarlo:

#!/usr/bin/env MyCustomPython
import 

Ancora un altro approccio è quello di disporre che lo script sia sia uno script shell valido (che carica il giusto interprete Python su se stesso) sia uno script valido nella lingua di destinazione (qui Python). Ciò richiede che tu trovi un modo per scrivere uno script in doppia lingua per la tua lingua di destinazione. In Perl, questo è noto come if $running_under_some_shell.

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

Ecco un modo per ottenere lo stesso effetto in Python. Nella shell, "true"è l' trueutilità, che ignora i suoi argomenti (due stringhe a carattere singolo :e ') e restituisce un valore vero. In Python, "true"è una stringa che è vera quando interpretata come booleana, quindi questa è ifun'istruzione che è sempre vera ed esegue una stringa letterale.

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

Il codice Rosetta ha tali script in doppia lingua in diverse altre lingue.


1
@Chris: tutto è racchiuso tra virgolette singole. Per favore, spiega ...
Stéphane Gimenez,

1
Sei un mago insanguinato ... È grandioso. Ho usato questo per modificare la PYTHONPATHvariabile env per caricare i moduli da una posizione non standard per uno script CGI su un sistema a cui non avevo accesso root. Salvavita. Grazie ancora.
wspurgin,

12

Le linee Shebang non subiscono espansione variabile, quindi non puoi usarle in $FOO/MyCustomPythonquanto cercherebbero un eseguibile chiamato dollar-FOO -...

Un'alternativa è che il tuo shebang punti a uno script di shell come interprete, e questo script di shell può quindi utilizzare le variabili di ambiente per individuare quella corretta ed eseguirla.

Esempio: crea uno mypython.shscript in /usr/local/bin(o qualsiasi altra directory sul tuo $PATH), con il seguente contenuto:

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

allora puoi usare questa riga di shebang per far eseguire uno script Python MyCustomPythontramite mypython.sh:

#!/usr/bin/env mypython.sh

6
Usa $python, non $PYTHON- per convenzione, capitalizziamo le variabili di ambiente (PAGER, EDITOR, SHELL ... $PYTHONnel tuo script non è una variabile di ambiente) e le variabili di shell interne (BASH_VERSION, RANDOM, ...). Tutti gli altri nomi di variabili devono contenere almeno una lettera minuscola. Questa convenzione evita di ignorare accidentalmente le variabili ambientali e interne. Inoltre, non utilizzare estensioni per i tuoi script. Gli script definiscono nuovi comandi che è possibile eseguire e ai comandi in genere non vengono assegnate estensioni.
Chris Down,

4

Puoi usare il percorso assoluto per l'installazione personalizzata di Python, oppure puoi inserirlo nel tuo $PATHe usare #!/usr/bin/env [command]. In caso contrario, scrivere un wrapper per esso e utilizzare execper sostituire l'immagine di processo, come esempio:

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

3

Innanzitutto, determina in che modo la tua versione di Python è diversa dallo standard Python già installato (ad esempio un modulo aggiuntivo) e quindi all'inizio del programma 'cambia' come viene chiamato 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

Ciò dovrebbe consentire al programma di essere chiamato da qualsiasi altra istanza di Python. Faccio qualcosa di simile per un'istanza con libreria sql integrata che non può essere importata come modulo nel pitone del sistema.


0

Se è possibile sostituire $FOOin $FOO/bar/MyCustomPythoncon opzioni percorso concreto, si può dire la envshebang dove andare a cercare la vostra versione personalizzata di Python impostando direttamente una consuetudine PATHin esso.

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

Modifica : sembra funzionare solo senza virgolette attorno all'assegnazione del valore PATH:

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

5
Attenzione che questo non funziona su tutte le varianti di unix (ad es. Non su Linux). E stai rimuovendo tutte le directory esistenti dal percorso, che probabilmente causerà problemi lungo la linea.
Gilles 'SO- smetti di essere malvagio' il

1
Meglio espandersi PATHcosì:PATH=$PATH:/path/to/whatever...
Bengt,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.