我收到错误
/usr/bin/env: zsh -: No such file or directory
...当我运行zsh
以以下 shebang 行开头的可执行脚本时:
#!/usr/bin/env zsh -
另外,FWIW,替换-
为打印类似投诉的--
原因。/usr/bin/env
zsh --
我只在 ubuntu 下看到过这个错误,并且只在 shebang hack 的上下文中见过。在达尔文下,相同的脚本运行良好。并且在ubuntu下,运行
% /usr/bin/env zsh -
从命令行成功。 (实际上,“under ubuntu”应该理解为“under ubuntu 12.04 LTS 和”的简写env (GNU coreutils) 8.13
。)
我的问题是:我该如何修改上面的shebang以避免这个错误?
当然,我知道删除尾随-
会消除错误,但这不是一个可接受的解决方案。这篇文章的其余部分解释了原因。
导致错误的 shebang 行是为了遵守两个完全独立的准则而出现的:
要使脚本可移植,请使用
#!/usr/bin/env <cmd ...>
而不是#!/path/to/cmd <...>
.将其作为zsh 脚本的 shebang 行中的
-
唯一参数会阻碍某些类型的zsh
攻击。
因此,我可以更准确地重申我的问题如下:是否可以在 ubuntu 下满足这两个准则而不触发上面显示的错误?
答案1
Linux(您提到“仅在 Ubuntu 下”,但您提到它工作的唯一操作系统是 Darwin)不支持将多个参数传递给“shebang”解释器。它将整个字符串(在您的情况下为"zsh -"
)作为单个参数传递。
确保您的软件包不依赖于解释器位置的正确方法是,作为安装过程的一部分,找到解释器并修改脚本以包含正确的路径。一些执行此操作的示例代码(对于sh
)提供于http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sh.html#tag_20_117_16。
答案2
我认为你的问题的答案基本上是“不”。 Shebang 机制并不那么灵活。
该#!
行仅允许您指定要执行的命令以及(可选)该命令的单个参数。脚本的名称作为另一个参数传递。所以如果foo.zsh
开始于:
#!/usr/bin/env zsh
跑步foo.zsh
就相当于跑步/usr/bin/env zsh foo.zsh
。
如果直接指定路径zsh
,则可以传递附加参数:
#!/usr/bin/zsh -
但随着#!/usr/bin/env
黑客的入侵,zsh
是附加参数。
显然,正如您所见,这种行为因系统而异。顺便说一句,我会检查以确保-
Ubuntu 上的 没有被忽略。
如果您可以依赖在zsh
您关心的所有系统上处于一致的位置,则可以使用#!/usr/bin/zsh -
(忽略您的第一个准则)。
如果不能,那么您可以zsh
在每个系统上的一致位置创建符号链接,也可以#!
在安装脚本时修改脚本中的行。 (在 Perl 并不总是存在的日子里,我自己为 Perl 脚本做过这个/usr/bin/perl
。)
或者,您可以编写一个包装器,当不带参数调用时,使用zsh
参数调用-
,并将 shebang 更改为:
#!/usr/bin/env zsh-wrapper
它只需要zsh-wrapper
位于 中的某个位置$PATH
,不一定位于一致的位置。
也可以看看这个问题和我对此的回答讨论该#!/usr/bin/env
黑客的优点和缺点。
并看到这一页有关各种类 Unix 系统上的 shebang 行为的更多信息(感谢 Stephane Chazelas 提供的链接)。