我试图弄清楚 shebang 的语义到底是什么。
我可以写一个这样的脚本:
#!/usr/bin/env bash
if [ -z "$FOO" ]
then
echo "No FOO"
else
echo "$FOO"
fi
在我的环境中没有,并像、、等$FOO
一样运行它,它将按预期打印“No FOO”。./foo.sh
bash foo.sh
env bash foo.sh
我当然可以像这样运行它FOO=bar ./foo.sh
并且它会打印bar
。
手册env
页给出的调用如下:
env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]
我可以这样使用它:
$ env FOO=bar bash foo.sh
bar
但是,如果我尝试在 shebang 中使用该语法:
#!/usr/bin/env FOO=bar bash
if [ -z "$FOO" ]
then
echo "No FOO"
else
echo "$FOO"
fi
然后./foo.sh
无限期挂起并且不执行。
谁可以给我解释一下这个?我假设当遇到 shebang 时,它只是复制命令,将脚本的路径附加到参数列表的末尾,然后执行它,但这种行为表明情况并非如此。
答案1
大多数系统只接受最多一shebang 行中解释器路径之后的参数。如果您提供多于一项,行为取决于系统。
在 Linux 上,解释器后面的所有内容(没有前导和尾随空格或制表符)都作为单个参数传递。所以,伴随着一声:
#! /usr/bin/env FOO=bar bash
系统将/usr/bin/env
使用FOO=bar bash
和/path/to/the/script
作为参数进行调用。然后将在其环境中env
再次运行脚本,而不是作为参数(在环境中),从而导致无限循环。FOO=bar bash
bash
/path/to/the/script
FOO=bar
的一些实现env
,包括 FreeBSD 和 GNU 的最新版本env
,可以被告知进行自身分割以-S
解决该限制。
在
#! /usr/bin/env -S FOO=bar bash
单个"-S FOO=bar bash"
参数仍将传递给env
,但env
会拆分" FOO=bar bash"
该-S
选项的参数,并且其行为就像使用FOO=bar
和bash
作为单独的参数调用一样。
请参阅GNUenv
手册或者FreeBSDenv
手册有关如何进行拆分的详细信息。