Что это
Когда ядро видит запрос на исполнение файла с битом +x, оно читает
первые два байта. Если это #! - называется shebang (или
hashbang) - следующая часть строки трактуется как путь к интерпретатору.
#!/usr/bin/env bash
echo hello
При вызове ./script.sh ядро видит #! → запускает
/usr/bin/env bash ./script.sh → env находит bash в $PATH →
bash интерпретирует скрипт.
Без #!, поведение зависит от того кто запускает:
- Из bash-шелла - bash сам выполнит как bash-скрипт
- Из dash/zsh/fish - может выполниться по правилам этого шелла
- Через
exec()без shell - ядро откажет с ENOEXEC
Поэтому всегда пиши shebang.
/bin/bash vs /usr/bin/env bash
Два варианта которые часто встречаются:
#!/bin/bash # хардкод пути
#!/usr/bin/env bash # ищем bash через PATH
Лучше второй. Причины:
| Сценарий | /bin/bash | /usr/bin/env bash |
|---|---|---|
macOS - bash 5 через brew в /usr/local/bin/bash | устаревший 3.x | свежий 5.x |
Alpine Linux - bash в /usr/bin/bash или вообще нет | не работает | работает если установлен |
NixOS - bash в /nix/store/.../bin/bash | не работает | работает |
| Стандартный Debian/Ubuntu | работает | работает |
Исключение - #!/bin/sh. POSIX гарантирует что POSIX-shell всегда
лежит в /bin/sh. Если скрипт реально POSIX-совместим - пиши
/bin/sh и не страдай.
Аргументы интерпретатору
В shebang можно передать один аргумент (Linux ограничение):
#!/usr/bin/env -S bash -euo pipefail
▸-S разбивает строку на токены (без -S весь "bash -euo pipefail" уйдёт как ОДИН аргумент)
Через env -S (требует coreutils 8.30+) можно вкорячить strict-mode
прямо в shebang. Альтернатива - set -euo pipefail первой строкой
скрипта.
Не только bash
Shebang работает с любым интерпретатором:
#!/usr/bin/env python3
print("hello from python")#!/usr/bin/env ruby
puts "hi"
#!/usr/bin/env node
console.log('hi')Идиома /usr/bin/env <interpreter> универсальна - работает для всех.
Типичные ошибки
- CRLF (Windows line endings) - ядро видит
#!/usr/bin/env bash\rи пытается найти интерпретаторbash\r. Ошибкаbad interpreter: No such file or directory. Решение:dos2unix file.sh. - Нет бита
+x-chmod +x file.sh. - Не указан полный путь -
#!bashне сработает, нужен абсолютный путь. - Shebang не на ПЕРВОЙ строке - ядро смотрит только на первые два байта, пустая строка перед shebang ломает магию.