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

Ang*_*rou 2 shell environment-variables shebang

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

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

#!/usr/bin/env bash

if [ -z "$FOO" ]
then
    echo "No FOO"
else
    echo "$FOO"
fi
Run Code Online (Sandbox Code Playgroud)

在我的环境中没有$FOO,并像 、 、 等一样运行它./foo.shbash foo.sh它将env bash foo.sh按预期打印“No FOO”。

我当然可以像这样运行它FOO=bar ./foo.sh并且它会打印bar

手册env页给出的调用如下:

env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]
Run Code Online (Sandbox Code Playgroud)

我可以这样使用它:

$ env FOO=bar bash foo.sh
bar
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试在 shebang 中使用该语法:

env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]
Run Code Online (Sandbox Code Playgroud)

然后./foo.sh无限期挂起并且不执行。

谁可以给我解释一下这个?我假设当遇到 shebang 时,它只是复制命令,将脚本的路径附加到参数列表的末尾,然后执行它,但这种行为表明情况并非如此。

Sté*_*las 5

大多数系统在 shebang 行中解释器路径之后最多只接受一个参数。如果您提供多个,则行为取决于系统

\n

在 Linux 上,解释器后面的所有内容(没有前导和尾随空格或制表符)都作为单个参数传递。所以,伴随着一声:

\n
#! /usr/bin/env FOO=bar bash\n
Run Code Online (Sandbox Code Playgroud)\n

系统将/usr/bin/env使用FOO=bar bash/path/to/the/script作为参数进行调用。然后env将在其环境中再次运行脚本FOO=bar bash,而不是bash作为/path/to/the/script参数(FOO=bar在环境中),从而导致无限循环。

\n

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

\n

\n
#! /usr/bin/env -S FOO=bar bash\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

有关如何完成拆分的详细信息,请参阅GNUenv手册FreeBSDenv手册。

\n