Mam skrypt w języku Python, który należy uruchomić z określoną instalacją w języku Python. Czy istnieje sposób na wykonanie shebang, aby działał $FOO/bar/MyCustomPython
?
Mam skrypt w języku Python, który należy uruchomić z określoną instalacją w języku Python. Czy istnieje sposób na wykonanie shebang, aby działał $FOO/bar/MyCustomPython
?
Odpowiedzi:
Linia shebang jest bardzo ograniczona. W wielu wariantach uniksowych (w tym Linux) możesz mieć tylko dwa słowa: polecenie i pojedynczy argument. Często występuje także ograniczenie długości.
Ogólnym rozwiązaniem jest napisanie małego opakowania powłoki. Nazwij skrypt Pythona foo.py
, umieść skrypt powłoki foo.py
i wywołaj go foo
. To podejście nie wymaga żadnego konkretnego nagłówka w skrypcie Python.
#!/bin/sh
exec "$FOO/bar/MyCustomPython" "$0.py" "$@"
Innym kuszącym podejściem jest napisanie skryptu opakowującego, takiego jak powyższy, i umieszczenie go #!/path/to/wrapper/script
jako linii shebang w skrypcie Python. Jednak większość jednorożców nie obsługuje tworzenia łańcuchów skryptów shebang, więc to nie zadziała.
Jeśli MyCustomPython
był w $PATH
, możesz to env
sprawdzić:
#!/usr/bin/env MyCustomPython
import …
Jeszcze innym podejściem jest skonfigurowanie skryptu, aby był zarówno poprawnym skryptem powłoki (który ładuje odpowiedni interpreter języka Python), jak i poprawnym skryptem w języku docelowym (tutaj Python). Wymaga to znalezienia sposobu na napisanie takiego dwujęzycznego skryptu dla języka docelowego. W Perlu jest to znane jako if $running_under_some_shell
.
#!/bin/sh
eval 'exec "$FOO/bar/MyCustomPerl" -wS $0 ${1+"$@"}'
if $running_under_some_shell;
use …
Oto jeden ze sposobów osiągnięcia tego samego efektu w Pythonie. W powłoce "true"
znajduje się true
narzędzie, które ignoruje argumenty (dwa ciągi jednoznakowe :
i '
) i zwraca prawdziwą wartość. W Pythonie "true"
łańcuch jest prawdziwy, gdy jest interpretowany jako wartość logiczna, więc jest to if
instrukcja, która zawsze jest prawdziwa i wykonuje literał łańcucha.
#!/bin/sh
if "true" : '''\'
then
exec "$FOO/bar/MyCustomPython" "$0" "$@"
exit 127
fi
'''
import …
Kod Rosetta ma takie dwujęzyczne skrypty w kilku innych językach.
PYTHONPATH
zmiennej env, aby załadować moduły ze niestandardowej lokalizacji dla skryptu CGI w systemie, do którego nie miałem dostępu do roota. Oszczędzanie życia Dzięki jeszcze raz.
Linie Shebang nie podlegają rozszerzaniu zmiennemu, więc nie można użyć, $FOO/MyCustomPython
ponieważ szukałby pliku wykonywalnego o nazwie dollar-FOO -...
Alternatywą jest, aby shebang wskazywał na skrypt powłoki jako interpreter, a ten skrypt powłoki może następnie użyć zmiennych środowiskowych do zlokalizowania poprawnego i wykonania go.
Przykład: utwórz mypython.sh
skrypt w /usr/local/bin
(lub innym katalogu na swoim $PATH
), o następującej treści:
#! /bin/sh
PYTHON="$FOO/bar/MyCustomPython"
exec "$PYTHON" "$@"
możesz użyć tej linii shebang, aby wykonać skrypt w języku Python MyCustomPython
poprzez mypython.sh
:
#!/usr/bin/env mypython.sh
$python
, a nie $PYTHON
- zgodnie z konwencją, kapitalizujemy zmienne środowiskowe (PAGER, EDITOR, SHELL ... $PYTHON
w twoim skrypcie nie jest zmienną środowiskową) i wewnętrzne zmienne powłoki (BASH_VERSION, RANDOM, ...). Wszystkie pozostałe nazwy zmiennych powinny zawierać co najmniej jedną małą literę. Konwencja ta pozwala uniknąć przypadkowego zastąpienia zmiennych środowiskowych i wewnętrznych. Nie używaj również rozszerzeń do swoich skryptów. Skrypty definiują nowe polecenia, które można uruchamiać, a na ogół polecenia nie mają rozszerzeń.
Możesz albo użyć bezwzględnej ścieżki do niestandardowej instalacji Pythona, albo umieścić ją w swojej $PATH
i używać #!/usr/bin/env [command]
. W przeciwnym razie napisz dla niego opakowanie i użyj exec
do zastąpienia obrazu procesu, na przykład:
#!/bin/bash
exec "$ENV/python" "$@"
Najpierw określ, w jaki sposób Twoja wersja Python różni się od standardowego już zainstalowanego Pythona (na przykład dodatkowy moduł), a następnie na początku programu „przełącz”, jak nazywa się 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
Powinno to umożliwić wywołanie programu przez dowolną inną instancję Pythona. Robię coś podobnego dla instancji z wbudowaną biblioteką SQL, której nie można zaimportować jako modułu w pythonie systemu.
Jeśli można zastąpić $FOO
w $FOO/bar/MyCustomPython
konkretnych opcji ścieżek, można powiedzieć env
shebang linię gdzie patrzeć niestandardową wersję Pythona bezpośrednio przez ustawienie niestandardowe PATH
w nim.
#!/usr/bin/env PATH="/path1/to/MyCustomPython:/path2/to/MyCustomPython" python
Edycja : Wydaje się, że działa tylko bez cudzysłowów wokół przypisania wartości PATH:
#!/usr/bin/env PATH=/path1/to/MyCustomPython:/path2/to/MyCustomPython python
PATH
ten sposób:PATH=$PATH:/path/to/whatever...