shebang

核心结论:shebang 不是 Bash 的语法,也不是某门编程语言的特性,是 Unix-like 操作系统内核的机制(magic number,魔数。内核 execve() 系统调用读取文件头两个字节 0x23 0x21(即 #!),拉起指定解释器,与脚本语言本身无关。

机制本质:内核魔数,不是语言语法

#! 位于脚本第一行开头,告诉操作系统用哪个解释器执行脚本。给文件加执行权限后直接 ./demo.sh 运行,内核读取文件开头,看到 #! 就取出后面的路径,启动对应解释器,并把脚本文件作为参数传给它。伪等价逻辑:./etl.py(有 shebang + chmod +x)实际约等于 /usr/bin/env python3 ./etl.py

这一行对解释器本身来说是注释。Bash、Python、Perl、Ruby 都把 # 当注释开头,读到直接丢弃;脚本语言根本不知道什么叫 shebang——是内核在 execve 时拦截解析,把脚本路径当参数丢给解释器。写了 shebang 也不要求解释器认识 #!,因为内核已经把这一行拿走了。

也因此只有直接执行才生效:

调用方式是否读取 shebang
./etl.py(chmod +x)✅ 内核解析 shebang
python3 etl.py / bash demo.sh❌ 内核直接调用解释器,#! 行被当成注释

词源

单词 shebang /ʃɪˈbæŋ/,别名 hash-bang、sha-bang、pound-bang。构词来自黑客俚语:# 在 Unix 圈叫 hash!bang(源自电传打字机时代,! 触发打印机猛敲一下的”bang”声);hash-bang 口语连读讹变为 shebang,拼写受英语原有旧词干扰固定下来。Dennis Ritchie 本人说过:开发这个内核特性时官方根本没有起名字,shebang 是社区事后叫出来的俗称。

英语原有一个 1860 年代美国内战俚语 shebang(棚屋、摊子),习语 the whole shebang 表示全部、整套。计算机术语与它没有语义继承,纯属拼法巧合的同形异义。中文译名释伴,音译加意译:解释器伴侣。

哪些语言能用

能用 shebang 需要三个前提:Unix-like 系统;存在可执行的解释器,能接收脚本文件作为命令行参数;解释器能容忍或跳过 #! 行。满足就能写:

#!/usr/bin/env bash        # shell
#!/usr/bin/env python3     # python
#!/usr/bin/env perl        # perl
#!/usr/bin/env ruby        # ruby
#!/usr/bin/env node        # javascript (NodeJS)
#!/usr/bin/env awk -f      # awk 脚本
#!/usr/bin/env lua         # lua

编译型语言(C/C++/Rust)不能也不需要——它们输出二进制可执行文件,开头是程序自己的魔数而非文本 #!。例外是提供脚本模式的执行器(go runrunhaskell),可以写 shebang 调它们,但不是主流用法。

注释符号不是 # 的语言照样能跑,比如 PHP(注释 //):

#!/usr/bin/env php
<?php
echo "hi";

内核照常解析 #! 交给 php 解释器,php 会主动跳过开头这一行——这是解释器为 Unix 做的兼容,不是语言语法。反过来,如果某个解释器不会自动跳过 #! 行,第一行就会被当成代码报错,shebang 便不可用。

Windows 原生内核不支持 shebang。Windows 的 Python 启动器是用户态程序做的模拟兼容,不是操作系统机制。

写法与坑

基本语法 #!/解释器路径 [可选参数]。路径有两种写法:硬编码绝对路径(#!/usr/bin/python3)会因不同机器解释器位置不同而报错;env 写法envPATH 里搜索解释器,适配不同机器,一律推荐:

#!/usr/bin/env python3
print("hello")

四个高频坑

  1. 必须是文件第一行,前面不能有空行或空格,否则 shebang 失效。
  2. Windows 换行符 CRLF:脚本在 Windows 编辑后传到 Linux,第一行变成 #!/usr/bin/env python3\r\r 被当成解释器名,报 bad interpreter: No such file or directory。修复:dos2unix script.py
  3. 直接执行需要 chmod +xpython3 script.py 不需要权限,但也无视 shebang。
  4. shebang 后只传一个参数#!/bin/bash -e 合法);多个参数(-e -u)跨平台行为不一致,不要写。

调度场景(crontab、Airflow)下,ETL 脚本第一行写 shebang,调度系统就能直接 ./etl.py./etl.sh,不必写死 python3 etl.py;不写也能跑,只是调用方必须显式指定解释器。