Я спробував таке, але, схоже, це не працює:
$ 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
. Зазвичай це два аргументи, -i
і /bin/sh
. Це лише обмеження шебангу. Нічого не обійти.
Однак ви все одно можете виконати це завдання, просто по-іншому.
Якщо ви хочете, щоб це завдання виконував сам сценарій, і вам не довелося робити щось на кшталт env -i script.sh
, ви можете змусити сценарій повторно виконувати себе.
#!/bin/sh
[ -z "$CLEANED" ] && exec /bin/env -i CLEANED=1 /bin/sh "$0" "$@"
Це призведе до повторного виконання сценарію, якщо CLEANED
змінна середовища не встановлена. Потім на re-exec він встановлює змінну, щоб переконатися, що вона не переходить у цикл.
env
від CoreNutil GNU тепер є можливість -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
Якщо ви маєте на увазі бігати з чистим середовищем, не кажучи прямо про це, коли біжите. Едуардо Іванец дає кілька ідей у цій відповіді , ви можете рекурсивно викликати свій сценарій, 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"
Обмеження шебанга для Linux-аргументів на 2 аргументи (інтерпетер + одиночний аргумент) відзначається у більшості відповідей, але сказати, що цього зробити не можна, невірно - потрібно просто перейти на інтерпретатора, який може зробити щось корисне за допомогою одного аргументу:
#!/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
аргументів) стародавня AT&T ksh93
робить:
#!/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
для очищення середовища.
Крім того, якщо прийнятно очищати навколишнє середовище на початку сценарію (лише для удару):
#!/bin/sh
unset $(compgen -e)
# your script here
Для цього використовується compgen
(помічник доповнення), щоб перелічити назви всіх експортованих змінних оточуючих середовищ, і unset
їх за один раз.
Дивіться також Кілька аргументів у shebang для отримання більш детальної інформації про загальну проблему поведінки shebang.