Як почати сценарій з чистого середовища?


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
Ви не можете зробити це з shebang. Шебанг може прийняти лише один аргумент.
jordanm

Відповіді:


7

Причина цього не працює в тому, що він розглядає -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. Будьте в курсі проблем з портативністю.
Вейджун Чжоу

3

Запустіть свій сценарій за допомогою env -i:

env -i script.sh

І сценарій, як завжди:

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

Якщо ви маєте на увазі бігати з чистим середовищем, не кажучи прямо про це, коли біжите. Едуардо Іванец дає кілька ідей у цій відповіді , ви можете рекурсивно викликати свій сценарій, execколи навколишнє середовище не є чистою (наприклад, $ HOME визначено):

[ "$HOME" != "" ] && exec -c $0

Приємно. Просто не робіть env -i баш як я, а потім дивуйтеся, чому ваші 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"

0

$ cat script.sh

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

На жаль, це не спрацює таким чином - Linux вважає -i /bin/shодним аргументом для передачі env(див. Shebang ).


0

Обмеження шебанга для 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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.