shebang 线不适用于 cr-lf

jam*_*gni 10 command-line newlines shebang

为什么以下基本脚本的 shebang 部分不起作用:

$ cat hello.sh
#! /bin/sh
echo Hello
$ ./hello.sh
bash: ./hello.sh: /bin/sh^M: bad interpreter: No such file or directory

$ cat hello.py
#! /usr/bin/env python3
print("Hello")
$ ./hello.py
: No such file or directory
Run Code Online (Sandbox Code Playgroud)

而手动调用解释器正在工作:

$ sh hello.sh
Hello
$ python3 hello.py
Hello
Run Code Online (Sandbox Code Playgroud)

jam*_*gni 11

你的脚本可能有 DOS 风格的 CR-LF 行尾,而不是 Unix 风格的 LF 行尾。在第一种情况下的错误消息中看到的 ^M 表明 0D 字符被解释为脚本解释器名称的一部分,而不是作为行尾的一部分(正如人们所期望的那样)。由于系统上没有包含字符 0D (^M) 的路径的可执行文件,因此系统无法调用解释器。当您手动调用解释器时,它能够处理脚本中存在的两种类型的行尾。

如果您将脚本转换为使用 Unix 样式的 LF 行结尾,您应该会看到 shebang 正常工作。继续阅读以获取插图。

在下面的会话中,todos 和 fromdos 是一个实用程序(在 Ubuntu 上作为包提供tofrodos)用于将行结束约定从 CR-LF 转换为 LF。任何等效的实用程序(请参阅此 unix.SE 问题)都可以用于演示目的。

以下会话记录(使用相同的脚本文件执行)应说明情况:

$ fromdos hello.sh
$ ./hello.sh
Hello
$ todos hello.sh
$ ./hello.sh
bash: ./hello.sh: /bin/sh^M: bad interpreter: No such file or directory
$
$ fromdos hello.py
$ ./hello.py
Hello
$ todos hello.py
$ ./hello.py
: No such file or directory
$
Run Code Online (Sandbox Code Playgroud)

似乎这是读取shebang行的内核,显然,Linux内核(至少在我的Kubuntu莽撞的系统上的版本)不能识别CR为结束约定CR-LF线的一部分。

如果您的脚本的shebang 似乎不起作用(即手动调用脚本上的解释器,但即使您已经完成chmod +x了它,您也无法使用其文件名执行脚本),那么这可能是一个原因。

注意:也 感谢其他评论者。我也很高兴听到是否有更好的答案!