Секрет первой строки скрипта 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. Как ядро выполняет скрипты?

Если сильно упростить, процесс выполнения выглядит так:

  1. Пользователь запускает скрипт с правами на выполнение.
chmod +x script.sh
./script.sh
  1. Ядро читает script.sh.
  2. Проверяет, являются ли первые два символа файла #!.
  3. Если да, то интерпретирует остальную часть строки как:
  • «путь к интерпретатору + аргументы»
  • и запускает эту программу, передавая ей путь к скрипту в качестве аргумента.

Например, если первая строка 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 в ней, затем запускает его.

Преимущества

  1. Переносимость (хорошо работает в различных средах)
  • Независимо от того, находится ли bash в /bin/bash, /usr/bin/bash или /usr/local/bin/bash,
  • env найдет его, если он корректно зарегистрирован в PATH.
  1. Использование bash, соответствующего пользовательской среде
  • Если пользователь настроил PATH для приоритетного использования определенной версии bash, то будет использоваться именно эта версия.
  1. Тот же шаблон используется для Python и других языков

python #!/usr/bin/env python3

Недостатки

  1. Предполагается наличие /usr/bin/env
  • Он присутствует практически во всех современных системах Unix/Linux, но в очень специфических окружениях его может не быть.
  1. Возможно использование другого интерпретатора в зависимости от PATH
  • Если настройки PATH некорректны или неожиданный bash оказывается первым в списке, может быть запущена нежелательная версия.
  1. Требует осторожности с точки зрения безопасности
  • В особо чувствительных к безопасности средах предпочтение может отдаваться абсолютным путям вместо поиска интерпретатора по 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 по умолчанию.
изображение shebang в скрипте Linux
shebang의 작동원리이미지