如何在干净的环境下启动脚本?


15

我尝试了以下操作,但似乎不起作用:

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

/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.

发现了类似的问题,但并没有说明如何从家当做:unix.stackexchange.com/questions/48994/...
balki

5
你不能从shebang做到这一点。shebang只能接受一个arg。
jordanm

Answers:


7

之所以不起作用,是因为它被-i /bin/sh视为的单个参数env。通常这将是2个参数,-i/bin/sh。这仅仅是shebang的一个局限。没办法。


但是,您仍然可以执行此任务,只是方法不同。

如果您希望此任务由脚本本身执行,而不必执行类似的操作env -i script.sh,则可以让脚本本身重新执行。

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

如果CLEANED未设置环境变量,这将导致脚本重新执行自身。然后在重新执行时,它会设置变量以确保它不会进入循环。


envGNU 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

真好 只是不要像我一样做env -i bash,然后想知道为什么仍然设置您的env变量(当然bash资源是.bashrc和朋友8)
Neil McGill

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 -eset -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参数的shebang限制(interpeter +单参数),但是不能做到这一点是不正确的-您只需更改为可以对单个参数做一些有用的事情的解释器即可:

#!/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包含脚本,但是使用shebang $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

而不是使用一个新变量这里使用了特殊的“ _”变量,如果没有设置精确“打击”然后替换脚本exec使用-a,使ARGV[0](因此$_庆典“并使用)只是” -c来清除环境。

或者,如果可以在脚本开始时清理环境(仅限bash),则:

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

使用compgen(补全助手)列出所有导出的环境变量的名称,然后unset一次性完成。

有关shebang行为的一般问题的更多详细信息,另请参见shebang中的Multiple arguments

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.