Я попробовал следующее, но это не похоже на работу:
$ cat script.sh
#!/bin/env -i /bin/sh
/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
Я попробовал следующее, но это не похоже на работу:
$ cat script.sh
#!/bin/env -i /bin/sh
/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
Ответы:
Причина, по которой это не работает, заключается в том, что он видит -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
. Помните о проблемах переносимости.
Запустите ваш скрипт с env -i
:
env -i script.sh
И сценарий как обычно:
#!/bin/sh
# ... your code here
Если вы хотите работать в чистом окружении без явного указания, когда вы запускаете. Эдуардо Иванец (Eduardo Ivanec) дает несколько идей в этом ответе : вы можете рекурсивно вызывать ваш скрипт, exec
когда среда не чистая (например, определен $ HOME):
[ "$HOME" != "" ] && exec -c $0
С 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"
В большинстве ответов отмечается ограничение Шебанга в 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
увидеть их за один раз.
Смотрите также Несколько аргументов в Шебанге для более подробной информации об общей проблеме поведения Шебанга.