带有 `#!/usr/bin/env 命令 --argument` 的 Shebang 行在 Linux 上失败

ram*_*ion 66 linux scripting executable env

我有一个简单的脚本:

#!/usr/bin/env ruby --verbose
# script.rb
puts "hi"
Run Code Online (Sandbox Code Playgroud)

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

osx% ./script.rb
hi
Run Code Online (Sandbox Code Playgroud)

但是,在我的 linux 机器上,它会引发错误

linux% ./script.rb
/usr/bin/env: ruby --verbose: No such file or directory
Run Code Online (Sandbox Code Playgroud)

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

linux% /usr/bin/env ruby --verbose ./script.rb
hi
Run Code Online (Sandbox Code Playgroud)

但是如果我打包ruby --verbose成一个参数,我可以复制错误env

linux% /usr/bin/env "ruby --verbose" ./script.rb
/usr/bin/env: ruby --verbose: No such file or directory
Run Code Online (Sandbox Code Playgroud)

所以我认为这是如何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.
Run Code Online (Sandbox Code Playgroud)

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

ram*_*ion 60

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

这已在 StackOverflow 上进行了广泛讨论

  • 规范失败。天哪。 (4认同)
  • 另请参阅 [此页面](http://www.in-ulm.de/~mascheck/various/shebang/) 以了解不同 Unices 上的行为。 (3认同)
  • 如果“规范失败”是指所有 Unix 系统都应该接受 1 个以上的参数,那么我 100% 同意您的意见:) (3认同)

小智 11

Coreutils>=8.30:

#!/usr/bin/env -S ruby --verbose
Run Code Online (Sandbox Code Playgroud)

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

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

在以下示例中:

#!/usr/bin/env perl -T -w print "hello\n";
Run Code Online (Sandbox Code Playgroud)

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

/usr/bin/env: 'perl -T -w': No such file or directory
Run Code Online (Sandbox Code Playgroud)

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

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

$ chmod a+x hello.pl $ ./hello.pl hello
Run Code Online (Sandbox Code Playgroud)

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

  • 是的。但愿意解释一下原因吗? (7认同)
  • 欢迎来到 Unix 和 Linux![简洁是可以接受的,但更全面的解释更好](https://unix.stackexchange.com/help/how-to-answer)。 (2认同)

小智 7

通过@rampion评论发现这个:

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

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