使用 `#!/usr/bin/env command --argument` 的 Shebang 行在 Linux 上失败

使用 `#!/usr/bin/env command --argument` 的 Shebang 行在 Linux 上失败

我有一个简单的脚本:

#!/usr/bin/env ruby --verbose
# script.rb
puts "hi"

在我的 OSX 机器上,它运行良好:

osx% ./script.rb
hi

然而,在我的linux机器上,它抛出一个错误

linux% ./script.rb
/usr/bin/env: ruby --verbose: No such file or directory

如果我手动运行 shebang 行,它工作正常

linux% /usr/bin/env ruby --verbose ./script.rb
hi

ruby --verbose但如果我将其打包到单个参数中,我可以复制该错误env

linux% /usr/bin/env "ruby --verbose" ./script.rb
/usr/bin/env: ruby --verbose: No such file or directory

env所以我认为这是如何解释 shebang 线重置的问题。我正在使用 GNU coreutils 8.4 env

linux% /usr/bin/env --version
env (GNU coreutils) 8.4
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Richard Mlynarik and David MacKenzie.

这看起来真的很奇怪。这是此版本的常见问题env,还是还有其他我不知道的问题?

答案1

看起来这是因为 Linux(与 BSD 不同)仅将单个参数传递给 shebang 命令(在本例中为 env)。

StackOverflow 上对此进行了广泛讨论

答案2

Coreutils>=8.30:

#!/usr/bin/env -S ruby --verbose

-S或env选项--split-string记录在 GNU coreutils 手册中(请参阅:info '(coreutils) env invocation'在线手册)。以下是摘录:

大多数操作系统(例如 GNU/Linux、BSD)将第一个空格之后的所有文本视为单个参数。因此,在脚本中使用 env 时,无法指定多个参数。

在以下示例中:

#!/usr/bin/env perl -T -w print "hello\n";

操作系统将其perl -T -w视为一个参数(程序名称),并且执行脚本失败并显示:

/usr/bin/env: 'perl -T -w': No such file or directory

-S选项指示env将单个字符串拆分为多个参数。以下示例按预期工作:

$ cat hello.pl
#!/usr/bin/env -S perl -T -w print "hello\n";

$ chmod a+x hello.pl $ ./hello.pl hello

相当于perl -T -w hello.pl在命令行提示符下运行。

答案3

通过@rampion 评论找到了这个:

发生的情况是内核处理文件的前两个字符来查找 #!。如果找到这些字符,那么它会跳过所有空格字符,寻找非空格字符,并提取解释器路径,该路径必须是真正的可执行文件,而不是另一个脚本,尽管 Linux 扩展了它以允许递归脚本处理。发现后,它会跳到第一个非空格字符,从那里到下一个换行符,并将其作为单个参数传递给命令。没有对引号或其他元字符进行“外壳”处理。这一切都非常简单且暴力。因此你不能对那里的选择感兴趣。您会得到一个包含空格的参数,而“perl -w”是内核在这里看到并传递的内容。

来源:http://lists.gnu.org/archive/html/bug-sh-utils/2002-04/msg00020.html

相关内容