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.pyi 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/scriptjako 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 MyCustomPythonbył w $PATH, możesz to envsprawdzić:
#!/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ę truenarzę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 ifinstrukcja, 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.
PYTHONPATHzmiennej 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/MyCustomPythonponieważ 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.shskrypt 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 MyCustomPythonpoprzez mypython.sh:
#!/usr/bin/env mypython.sh
$python, a nie $PYTHON- zgodnie z konwencją, kapitalizujemy zmienne środowiskowe (PAGER, EDITOR, SHELL ... $PYTHONw 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 $PATHi używać #!/usr/bin/env [command]. W przeciwnym razie napisz dla niego opakowanie i użyj execdo 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ć $FOOw $FOO/bar/MyCustomPythonkonkretnych opcji ścieżek, można powiedzieć envshebang linię gdzie patrzeć niestandardową wersję Pythona bezpośrednio przez ustawienie niestandardowe PATHw 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
PATHten sposób:PATH=$PATH:/path/to/whatever...