Секрет первой строки скрипта Linux: Что это за #!/usr/bin/env bash и #!/bin/bash?
При создании скриптов в Linux принято по умолчанию добавлять в самом начале одну из этих строк:
#!/usr/bin/env bash
или
#!/bin/bash
На первый взгляд они похожи на комментарии, но каково их истинное предназначение? И в чем разница между ними? В этой статье мы разберемся в значении этих строк и выясним, когда какую из них следует использовать.
1. Это не комментарий: Что такое shebang (шебанг)?
Строка, начинающаяся с #!, называется shebang (шебанг).
#!/bin/bash
Для оболочки (shell) строка, начинающаяся с #, выглядит как обычный комментарий. Однако для операционной системы (ядра) это не комментарий, а:
«Директива, указывающая, где находится программа-интерпретатор, которая должна выполнить этот скрипт».
То есть:
#!/bin/bash→ «Выполни этот файл с помощью/bin/bash»#!/usr/bin/env bash→ «Найди интерпретаторbashчерезenvи выполни этот файл с его помощью»
2. Как ядро выполняет скрипты?
Если сильно упростить, процесс выполнения выглядит так:
- Пользователь запускает скрипт с правами на выполнение.
chmod +x script.sh
./script.sh
- Ядро читает
script.sh. - Проверяет, являются ли первые два символа файла
#!. - Если да, то интерпретирует остальную часть строки как:
- «путь к интерпретатору + аргументы»
- и запускает эту программу, передавая ей путь к скрипту в качестве аргумента.
Например, если первая строка script.sh выглядит так:
#!/bin/bash
то ядро фактически выполняет что-то вроде:
/bin/bash script.sh
То есть, ядро выполняет действие, аналогичное тому, как если бы мы сами запустили bash script.sh.
Примечание: Перед
#!/не должно быть пробелов. Первым символом файла должен быть#, вторым —!.
3. Значение и особенности #!/bin/bash
Самая распространенная форма выглядит так:
#!/bin/bash
Значение
- «Этот скрипт является bash-скриптом, а
bashнаходится по пути/bin/bash.» - Ядро всегда запускает
/bin/bashпри выполнении этого скрипта.
Преимущества
- Ясность: Всегда используется
/bin/bash, что облегчает предсказание, какая версия bash будет задействована. - Производительность/Простота: Выполнение происходит напрямую, без использования
env, что исключает процесс поиска по путям. - Во многих дистрибутивах Linux
/bin/bashфактически считается «стандартным расположением».
Недостатки
-
Может быть непереносимым
-
В некоторых системах bash может находиться по другому пути, например,
/usr/bin/bashили/usr/local/bin/bash. - В некоторых системах bash может быть вообще не установлен, и доступен только
/bin/sh. - В частности, в macOS, системах на базе BSD, NixOS и некоторых контейнерных средах пути могут отличаться.
4. Значение и особенности #!/usr/bin/env bash
В современных скриптах часто встречается именно эта форма:
#!/usr/bin/env bash
Ключевым здесь является /usr/bin/env.
-
env— это утилита, которая помогает «устанавливать/проверять переменные окружения + искать программы в PATH». -
Можно считать, что ядро фактически выполняет это так:
bash
/usr/bin/env bash script.sh
envпросматривает переменную окруженияPATHсистемы и находит исполняемый файлbashв ней, затем запускает его.
Преимущества
- Переносимость (хорошо работает в различных средах)
- Независимо от того, находится ли bash в
/bin/bash,/usr/bin/bashили/usr/local/bin/bash, envнайдет его, если он корректно зарегистрирован вPATH.
- Использование bash, соответствующего пользовательской среде
- Если пользователь настроил
PATHдля приоритетного использования определенной версии bash, то будет использоваться именно эта версия.
- Тот же шаблон используется для Python и других языков
python
#!/usr/bin/env python3
Недостатки
- Предполагается наличие
/usr/bin/env
- Он присутствует практически во всех современных системах Unix/Linux, но в очень специфических окружениях его может не быть.
- Возможно использование другого интерпретатора в зависимости от PATH
- Если настройки PATH некорректны или неожиданный bash оказывается первым в списке, может быть запущена нежелательная версия.
- Требует осторожности с точки зрения безопасности
- В особо чувствительных к безопасности средах предпочтение может отдаваться абсолютным путям вместо поиска интерпретатора по PATH.
5. Сравнение двух подходов
Давайте кратко сравним их в таблице.
| Критерий | #!/bin/bash | #!/usr/bin/env bash |
|---|---|---|
| Способ указания пути к интерпретатору | Фиксированный абсолютный путь | Поиск через PATH |
| Переносимость (совместимость с разными системами) | Низкая (ломается при изменении пути) | Высокая (достаточно наличия bash в PATH) |
| Какой bash используется | Всегда /bin/bash |
Первый найденный bash в PATH |
| Гарантия нужной версии | Относительно легко | Может зависеть от состояния PATH |
| Безопасность/Контроль | Выше (фиксированный путь) | Немного слабее (зависимость от PATH) |
| Общие современные тенденции | Относительно старый стиль | В последнее время чаще рекомендуется |
6. Когда что использовать?
Отвечая на вопрос «Что же мне в итоге использовать?», рассмотрим различные сценарии.
1) Скрипты для личного использования / командной разработки (типичная среда разработки)
- Как правило, рекомендуется следующее:
bash
#!/usr/bin/env bash
-
Причины:
-
Расположение bash может отличаться на серверах, в локальных средах, CI-средах, управляемых разработчиками.
- Поиск и выполнение на основе PATH более гибок, и современные инструменты/скрипты предпочитают этот метод.
2) Операционные скрипты, строго соответствующие определенной серверной среде
-
Например, если на всех серверах компании bash установлен по общему пути
/bin/bash, -
и серверная среда достаточно статична, то:
bash
#!/bin/bash
-
Причины:
-
Гарантирует использование одного и того же интерпретатора.
- Помогает избежать неожиданного поведения из-за изменений PATH.
3) Если вы хотите сделать скрипт максимально переносимым?
-
Если вы предполагаете, что bash может отсутствовать в среде, стоит задуматься, должен ли скрипт вообще зависеть от bash.
-
Если возможно, пишите на
sh:
bash
#!/bin/sh
- Этот подход работает в гораздо более широком спектре сред. Однако при этом нельзя использовать синтаксис, специфичный для bash (двойные квадратные скобки, массивы, расширенная обработка строк и т.д.).
7. Практические советы при использовании #!/usr/bin/env bash
1) Как запускать скрипты
Чтобы shebang работал корректно, не стоит просто делать так:
bash script.sh # ← При таком запуске shebang практически не имеет значения
Лучше использовать следующий метод:
chmod +x script.sh # Предоставить права на выполнение
./script.sh # Запустить напрямую
Только так ядро сможет прочитать #! и использовать указанный интерпретатор.
2) Проверка передачи аргументов
Предположим, мы создали test.sh следующим образом:
#!/usr/bin/env bash
echo "Интерпретатор: $0"
echo "Аргументы: $@"
Запуск:
chmod +x test.sh
./test.sh hello world
Вывод:
Интерпретатор: ./test.sh
Аргументы: hello world
Здесь $0 — это «путь к самому файлу скрипта», и достаточно помнить, что ядро фактически выполняет команду вроде /usr/bin/env bash test.sh hello world.
8. Часто задаваемые вопросы
Я видел скрипты, написанные без shebang. Это нормально?
-
Верно, он не всегда обязателен.
-
Если вы запускаете скрипт, явно указывая интерпретатор, как показано ниже, shebang не нужен и даже игнорируется, если он присутствует:
bash
bash myscript.sh
python3 myscript.py
- Однако, если вы хотите запускать скрипт так:
bash
./myscript.sh
./myscript.py
- то shebang абсолютно необходим. Особенно, если это «инструментальный» скрипт, который могут использовать другие, shebang почти обязателен.
«А разве #!/bin/env вместо #!/usr/bin/env тоже не работает?»
- В некоторых системах
/bin/envдействительно может существовать. - Однако
/usr/bin/envявляется гораздо более универсальным и стандартным расположением. - Если нет особых причин, безопаснее использовать
#!/usr/bin/env ….
9. Краткое содержание
#!/usr/bin/env bashили#!/bin/bash— это не комментарии, а директивы для ядра, указывающие, каким интерпретатором следует выполнить скрипт.-
#!/bin/bash -
Всегда использует
/bin/bash→ предсказуемо в фиксированных средах, но может быть непереносимым. -
#!/usr/bin/env bash -
Ищет bash в
PATH→ более гибкий и переносимый, но зависит от состояния PATH. - В общих средах разработки/развертывания, при написании скриптов в «современном стиле», рекомендуется использовать
#!/usr/bin/env bashпо умолчанию.
