Como posso usar variáveis ​​de ambiente no meu shebang?


34

Eu tenho um script Python que precisa ser executado com uma instalação python específica. Existe uma maneira de criar um shebang para que ele funcione $FOO/bar/MyCustomPython?

Respostas:


29

A linha shebang é muito limitada. Sob muitas variantes do unix (incluindo Linux), você pode ter apenas duas palavras: um comando e um único argumento. Também há frequentemente uma limitação de comprimento.

A solução geral é escrever um pequeno invólucro de casca. Nomeie o script Python foo.pye coloque o shell script ao lado foo.pye chame-o foo. Essa abordagem não requer nenhum cabeçalho específico no script Python.

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

Outra abordagem tentadora é escrever um script wrapper como o descrito acima e colocar #!/path/to/wrapper/scriptcomo a linha shebang no script Python. No entanto, a maioria dos unices não suporta encadeamento de scripts shebang, portanto, isso não funcionará.

Se MyCustomPythonestava no $PATH, você pode usar envpara procurar:

#!/usr/bin/env MyCustomPython
import …

Outra abordagem é organizar para que o script seja um script shell válido (que carrega o interpretador Python correto em si mesmo) e um script válido na linguagem de destino (aqui Python). Isso requer que você encontre uma maneira de escrever um script em dois idiomas para o seu idioma de destino. No Perl, isso é conhecido como if $running_under_some_shell.

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

Aqui está uma maneira de obter o mesmo efeito no Python. No shell, "true"é o trueutilitário, que ignora seus argumentos (duas cadeias de caracteres únicos :e ') e retorna um valor verdadeiro. No Python, "true"é uma string que é verdadeira quando interpretada como booleana; portanto, esta é uma ifinstrução que é sempre verdadeira e executa uma literal de string.

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

O código Rosetta possui scripts de dois idiomas em vários outros idiomas.


11
@ Chris: tudo está dentro de aspas simples. Por favor, explique…
— Stéphane Gimenez

11
Você é um maldito bruxo ... Isso é ótimo. Usei isso para editar a PYTHONPATHvariável env para carregar módulos de um local não padrão para um script CGI em um sistema ao qual não tinha acesso root. Poupança de vida. Obrigado novamente.
— Wspurgin

12

As linhas Shebang não sofrem expansão variável; portanto, você não pode usá- $FOO/MyCustomPythonlo, pois ele procuraria por um executável chamado dollar-FOO -...

Uma alternativa é fazer com que seu shebang aponte para um script de shell como intérprete, e esse script de shell pode usar variáveis ​​de ambiente para localizar o correto e executá-lo.

Exemplo: crie um mypython.shscript /usr/local/bin(ou qualquer outro diretório no seu $PATH), com o seguinte conteúdo:

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

então você pode usar esta linha shebang para executar um script Python MyCustomPythonatravés de mypython.sh:

#!/usr/bin/env mypython.sh

6
Use $python, não $PYTHONpor convenção, capitalizamos variáveis ​​de ambiente (PAGER, EDITOR, SHELL ... $PYTHONem seu script não é uma variável de ambiente) e variáveis ​​internas do shell (BASH_VERSION, RANDOM, ...). Todos os outros nomes de variáveis ​​devem conter pelo menos uma letra minúscula. Esta convenção evita a substituição acidental de variáveis ​​ambientais e internas. Além disso, não use extensões para seus scripts. Os scripts definem novos comandos que você pode executar, e os comandos geralmente não recebem extensões.
— Chris Baixo

4

Você pode usar o caminho absoluto para a instalação customizada do python ou pode colocá-lo no seu $PATHe use #!/usr/bin/env [command]. Caso contrário, escreva um wrapper para ele e use-o execpara substituir a imagem do processo, como um exemplo:

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

3

Primeiro, determine como a sua versão do Python é diferente do Python padrão já instalado (por exemplo, um módulo adicional) e, em seguida, no início do programa 'switch', como o Python é chamado:

#!/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

Isso deve permitir que o programa seja chamado por qualquer outra instância do Python. Faço algo semelhante para uma instância com a biblioteca sql interna que não pode ser importada como um módulo no python do sistema.


0

Se você pode substituir $FOOpor $FOO/bar/MyCustomPythonopções de caminho concreto, pode dizer à envlinha shebang onde procurar sua versão personalizada do Python, definindo diretamente um personalizado PATH.

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

Editar : parece funcionar apenas sem aspas na atribuição de valor PATH:

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

5
Cuidado que isso não funciona em todas as variantes do unix (por exemplo, não no Linux). E você está removendo todos os diretórios existentes do caminho, o que provavelmente causará problemas na linha.
— Gilles 'SO- stop being evil'

11
Melhor expandir PATHassim:PATH=$PATH:/path/to/whatever...
— Bengt
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.