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.
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.
Odpowiedzi:
Powodem tego nie jest to, że traktuje to -i /bin/sh
jako pojedynczy argument env
. Zwykle byłyby to 2 argumenty -i
i /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 CLEANED
zmienna środowiskowa nie jest ustawiona. Następnie przy ponownym wykonaniu ustawia zmienną, aby upewnić się, że nie przechodzi ona w pętlę.
env
z jądra GNU mają teraz możliwość -S
obejścia problemów podobnych do tego, ale nie dokładnie takich samych. Na przykład #!/usr/bin/env -S perl -T
.
#!/usr/bin/env -S -i /bin/sh
. Pamiętaj o problemach z przenośnością.
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, exec
gdy środowisko nie jest czyste (np. Zdefiniowano $ HOME):
[ "$HOME" != "" ] && exec -c $0
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 -e
i 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 -e
ustawieniem.
Testowanie HOME
zmiennej 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"
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 perl
ze 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 perl
razie potrzeby można dodać dalszą logikę (choć niewiele w Linuksie, ponieważ jesteś ograniczony do BINPRM_BUF_SIZE
znakó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: - /
perl
przetwarza 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, @ARGV
zwykle zawiera tylko argumenty i $0
skrypt, ale z tym shebangiem $ARGV[0]
jest nazwa skryptu (i $0
jest -e
), co czyni to trochę łatwiejszym.
Możesz również rozwiązać ten problem za pomocą interpretera, który „przetwarza” linię poleceń (bez dodatkowego -c
argumentu), co starożytne AT&T ksh93
:
#!/bin/ksh /usr/bin/env -i /bin/sh
choć może ksh
nie jest tak powszechne w dzisiejszych czasach ;-)
( bash
ma 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 exec
użyciem -a
zrobić ARGV[0]
(i stąd $_
) tylko „bash”, a przy użyciu -c
oczyś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 unset
s je za jednym razem.
Zobacz także Wiele argumentów w shebang, aby uzyskać więcej informacji na temat ogólnego problemu zachowania shebang.