Jak uruchomić skrypt w czystym środowisku?

15

Próbowałem następujące, ale wydaje się, że nie działa:

$ cat script.sh
#!/bin/env -i /bin/sh

/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
balki
źródło
Znaleziono podobne pytania, ale nie pokazuje, jak to zrobić z shebang
balki
5
Nie możesz tego zrobić z shebang. Shebang może zaakceptować tylko jeden argument.
Jordan

Odpowiedzi:

7

Powodem tego nie jest to, że traktuje to -i /bin/shjako pojedynczy argument env. Zwykle byłyby to 2 argumenty -ii /bin/sh. To tylko ograniczenie shebang. Nie da się tego obejść.


Jednak nadal możesz wykonać to zadanie, po prostu w inny sposób.

Jeśli chcesz, aby to zadanie zostało wykonane przez sam skrypt i nie musisz robić czegoś takiego env -i script.sh, możesz ponownie uruchomić skrypt.

#!/bin/sh
[ -z "$CLEANED" ] && exec /bin/env -i CLEANED=1 /bin/sh "$0" "$@"

Spowoduje to ponowne wykonanie skryptu, jeśli CLEANEDzmienna środowiskowa nie jest ustawiona. Następnie przy ponownym wykonaniu ustawia zmienną, aby upewnić się, że nie przechodzi ona w pętlę.

Patrick
źródło
envz jądra GNU mają teraz możliwość -Sobejścia problemów podobnych do tego, ale nie dokładnie takich samych. Na przykład #!/usr/bin/env -S perl -T.
Weijun Zhou
Po prostu próbowałem. Działa to również w przypadku pierwotnego pytania. Po prostu użyj #!/usr/bin/env -S -i /bin/sh. Pamiętaj o problemach z przenośnością.
Weijun Zhou
3

Uruchom skrypt za pomocą env -i:

env -i script.sh

I skrypt jak zwykle:

#!/bin/sh
# ... your code here

Jeśli chcesz uruchomić w czystym środowisku, nie mówiąc wprost o tym podczas uruchamiania. Eduardo Ivanec podaje kilka pomysłów w tej odpowiedzi , możesz rekurencyjnie wywoływać skrypt, execgdy środowisko nie jest czyste (np. Zdefiniowano $ HOME):

[ "$HOME" != "" ] && exec -c $0
RSFalcon7
źródło
Ładny. Po prostu nie rób env -i bash jak ja, a potem zastanawiam się, dlaczego zmienne env są nadal ustawione (oczywiście zasoby bash .bashrc i przyjaciele 8)
Neil McGill
2

Dzięki bash możesz to zrobić w następujący sposób:

#!/usr/bin/bash

set -e
set -u

[ -v HOME ] && exec -c "$0" "$@"

# continue with the rest of the script
# e.g. print the cleaned environment:
export

Polecenia set -ei set -u nie są absolutnie konieczne, ale dołączam je, aby wykazać, że to podejście nie polega na uzyskiwaniu dostępu do nieuzbrojonych zmiennych (jak np. [ "$HOME" != "" ]) I jest zgodne z set -eustawieniem.

Testowanie HOMEzmiennej powinno być bezpieczne, ponieważ bash wykonuje skrypty w trybie nieinteraktywnym, tzn. Pliki konfiguracyjne takie jak ~/.bashrc(gdzie można ustawić zmienne środowiskowe) nie są pozyskiwane podczas uruchamiania.

Przykładowe dane wyjściowe:

declare -x OLDPWD
declare -x PWD="/home/juser"
declare -x SHLVL="1"
maxschlepzig
źródło
0

$ cat script.sh

#!/bin/env -i /bin/sh

Niestety nie zadziała w ten sposób - Linux uważa, -i /bin/shże należy przekazać jeden argument env(patrz Shebang ).

poige
źródło
0

W większości odpowiedzi odnotowano ograniczenie linuksowego 2-argumentowego ograniczania (interpeter + pojedynczy argument), ale stwierdzenie, że nie można tego zrobić, jest niepoprawne - wystarczy zmienić na interpretera, który może zrobić coś użytecznego za pomocą jednego argumentu:

#!/usr/bin/perl -we%ENV=();exec "/bin/sh " . join " ", map "'$_'", @ARGV;
# your sh script here

Co to robi to invoke perlze skryptem jedną liniowej ( -e), która czyści %ENV(tańsze niż env -i) i wywołuje exec /bin/sh, właściwego zacytowania argumentów. W perlrazie potrzeby można dodać dalszą logikę (choć niewiele w Linuksie, ponieważ jesteś ograniczony do BINPRM_BUF_SIZEznaków, co prawdopodobnie wynosi 128)

Niestety, jest to specyficzne dla Linuksa, nie będzie działać w systemie, który pozwala na wiele argumentów shebang: - /

perlprzetwarza ten ciąg jako pojedynczy argument, więc nie jest cytowany powyżej, jak to zwykle bywało z perl -e ...linii poleceń (jeśli chcesz dodać cudzysłowy, są one zachowane, perl widzi tylko dosłowny ciąg, z ostrzeżeniami narzeka na bezużyteczne stały).

Zauważ też, że przy takim stosowaniu zachowuje się niewielka zmiana, @ARGVzwykle zawiera tylko argumenty i $0skrypt, ale z tym shebangiem $ARGV[0]jest nazwa skryptu (i $0jest -e), co czyni to trochę łatwiejszym.

Możesz również rozwiązać ten problem za pomocą interpretera, który „przetwarza” linię poleceń (bez dodatkowego -cargumentu), co starożytne AT&T ksh93:

#!/bin/ksh /usr/bin/env -i /bin/sh

choć może kshnie jest tak powszechne w dzisiejszych czasach ;-)

( bashma podobną funkcję --wordexp, ale jest „nieudokumentowany” w wersjach, w których działa, i nie jest włączony w czasie kompilacji w wersjach, w których jest udokumentowany: - / Nie można go również użyć do tego, ponieważ wymaga dwóch argumentów. ..)

Również skutecznie odmiana odpowiedzi @Patrick i @ maxschlepzig:

#!/bin/bash
[ "$_" != bash ] && exec -c -a "bash" /bin/bash "$0" "$@"
# your script here

Zamiast używać nowy Zmienna ta wykorzystuje specjalne „ _” zmienna, jeśli nie jest ustawiona dokładnie „bash”, a następnie zastąpić skrypt z execużyciem -azrobić ARGV[0](i stąd $_) tylko „bash”, a przy użyciu -coczyścić środowisko.

Alternatywnie, jeśli dopuszczalne jest czyszczenie środowiska na początku skryptu (tylko bash):

#!/bin/sh
unset $(compgen -e)
# your script here

Wykorzystuje compgen(pomocnik uzupełniania), aby wyświetlić listę nazw wszystkich eksportowanych zmiennych środowiskowych, i unsets je za jednym razem.

Zobacz także Wiele argumentów w shebang, aby uzyskać więcej informacji na temat ogólnego problemu zachowania shebang.

pan. spuratic
źródło