Как запустить скрипт с чистой средой?

15

Я попробовал следующее, но это не похоже на работу:

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

/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
Балки
источник
Нашел похожие вопросы, но не показывает, как это сделать с shebang: unix.stackexchange.com/questions/48994/…
balki
5
Вы не можете сделать это из Шебанга. Шебанг может принять только один аргумент.
Иордания

Ответы:

7

Причина, по которой это не работает, заключается в том, что он видит -i /bin/shв качестве единственного аргумента env. Обычно это будет 2 аргумента, -iи /bin/sh. Это всего лишь ограничение Шебанга. Обойти это невозможно.


Однако вы все еще можете выполнить эту задачу, просто по-другому.

Если вы хотите, чтобы эта задача выполнялась самим сценарием, и вам не приходилось делать что-то подобное env -i script.sh, вы можете заставить сценарий повторно выполнить сам.

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

Это заставит скрипт повторно выполнить себя, если CLEANEDпеременная окружения не установлена. Затем при повторном запуске он устанавливает переменную, чтобы убедиться, что она не входит в цикл.

Патрик
источник
envиз GNU coreutils теперь есть возможность -Sобойти проблемы, похожие на эту, но не совсем те же. Например #!/usr/bin/env -S perl -T.
Вейцзюнь Чжоу
Только что попробовал. Это работает и для оригинального вопроса. Просто используйте #!/usr/bin/env -S -i /bin/sh. Помните о проблемах переносимости.
Вейцзюнь Чжоу
3

Запустите ваш скрипт с env -i:

env -i script.sh

И сценарий как обычно:

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

Если вы хотите работать в чистом окружении без явного указания, когда вы запускаете. Эдуардо Иванец (Eduardo Ivanec) дает несколько идей в этом ответе : вы можете рекурсивно вызывать ваш скрипт, execкогда среда не чистая (например, определен $ HOME):

[ "$HOME" != "" ] && exec -c $0
RSFalcon7
источник
Ницца. Только не делайте env -i bash, как я, а затем удивляйтесь, почему ваши переменные env все еще установлены (конечно, ресурсы bash .bashrc и друзья 8)
Нил МакГилл
2

С bash вы можете сделать это так:

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

set -eИ set -u команды не являются строго необходимыми, но я включаю их , чтобы продемонстрировать , что этот подход не зависит от доступа к неустановленные переменные (как , например , [ "$HOME" != "" ]будет) и совместим с set -eустановкой.

Тестирование HOMEпеременной должно быть безопасным, потому что bash выполняет сценарии в неинтерактивном режиме, то есть файлы конфигурации, такие как ~/.bashrc(где могут быть установлены переменные среды), не создаются при запуске.

Пример вывода:

declare -x OLDPWD
declare -x PWD="/home/juser"
declare -x SHLVL="1"
maxschlepzig
источник
0

$ cat script.sh

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

К сожалению, это не сработает - Linux рассматривает -i /bin/shкак один аргумент для передачи env(см. Шебанг ).

poige
источник
0

В большинстве ответов отмечается ограничение Шебанга в 2-х аргументах Linux (interpeter + single аргумент), но сказать, что это невозможно, неверно - вам просто нужно перейти к интерпретатору, который может сделать что-то полезное с одним аргументом:

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

Что это делает, так это вызывает perlоднострочный скрипт ( -e), который очищает %ENV(дешевле чем env -i) и вызывает exec /bin/sh, правильно цитируя аргументы. При необходимости perlможно добавить дополнительную логику (хотя в Linux не так много, так как вы ограничены BINPRM_BUF_SIZEсимволами, что, вероятно, 128)

К сожалению, это специфично для Linux, оно не будет работать в системе, которая допускает множественные аргументы shebang: - /

perlобрабатывает эту строку как один аргумент, поэтому она не цитируется выше, как вы обычно делаете perl -e ...из командной строки (если вы добавите кавычки, они сохранятся, perl увидит только буквенную строку, а предупреждения на ней будут жаловаться на бесполезную константа).

Также обратите внимание, что при использовании этого способа происходит небольшое изменение в поведении, которое @ARGVобычно содержит только аргументы и $0содержит сценарий, но с этим шебангом $ARGV[0]является имя сценария (и $0есть -e), что делает его немного проще.

Вы также можете решить эту проблему с помощью интерпретатора, который «перерабатывает» свою командную строку (без дополнительного -cаргумента), что ksh93делает древний AT & T :

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

хотя, возможно ksh, не так часто в настоящее время ;-)

( bashимеет аналогичную функцию с --wordexp, но она «недокументирована» в версиях, где она работает, и не включена во время компиляции в версиях, где она документирована: - / Она также не может быть использована для этого, так как для нее требуется два аргумента. ..)

Кроме того, эффективная вариация ответов @Patrick и @ maxschlepzig:

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

Вместо того, чтобы использовать новую переменную, она использует специальную _переменную " ", если она не установлена ​​точно на "bash", то замените скрипт на execиспользование, -aчтобы сделать ARGV[0](и, следовательно, " $_просто" bash ", и использование -cдля очистки среды.

В качестве альтернативы, если допустимо очищать среду в начале скрипта (только bash):

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

Это использует compgen(завершение), чтобы перечислить имена всех экспортируемых переменных окружения, и unsetувидеть их за один раз.

Смотрите также Несколько аргументов в Шебанге для более подробной информации об общей проблеме поведения Шебанга.

mr.spuratic
источник