#!/usr/bin/env 因 NAME=VALUE 而挂起

#!/usr/bin/env 因 NAME=VALUE 而挂起

我试图弄清楚 shebang 的语义到底是什么。

我可以写一个这样的脚本:

#!/usr/bin/env bash

if [ -z "$FOO" ]
then
    echo "No FOO"
else
    echo "$FOO"
fi

在我的环境中没有,并像、、等$FOO一样运行它,它将按预期打印“No FOO”。./foo.shbash foo.shenv 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 bashbash/path/to/the/scriptFOO=bar

的一些实现env,包括 FreeBSD 和 GNU 的最新版本env,可以被告知进行自身分割以-S解决该限制。

#! /usr/bin/env -S FOO=bar bash

单个"-S FOO=bar bash"参数仍将传递给env,但env会拆分" FOO=bar bash"-S选项的参数,并且其行为就像使用FOO=barbash作为单独的参数调用一样。

请参阅GNUenv手册或者FreeBSDenv手册有关如何进行拆分的详细信息。

相关内容