Секрет первой строки в скриптах Линукс: Что такое #!/usr/bin/env bash и #!/bin/bash?

Когда вы пишете скрипты в Линукс, то по привычке добавляете в самом начале одну из этих строк:

#!/usr/bin/env bash

или

#!/bin/bash

На первый взгляд, это похоже на обычный комментарий… Но что на самом деле скрывается за этой строкой? И в чем заключаются их различия? В этой статье мы подробно разберем значение этой строки и выясним, когда какой вариант следует использовать.


1. Это не комментарий: Что такое shebang?

Строка, начинающаяся с #!, называется shebang.

#!/bin/bash

Для оболочки это выглядит как комментарий, поскольку она начинается с #. Однако для операционной системы (ядра) это не комментарий, а:

"Директива, указывающая, где находится программа-интерпретатор, которая должна выполнить этот скрипт."

То есть:

  • #!/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, что исключает процесс поиска пути.
  • Многие дистрибутивы Линукс рассматривают /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.

  • Можно считать, что ядро фактически выполняет это так:

/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 в первую очередь, то именно эта версия bash будет использоваться.
  1. Используется тот же шаблон для Python и других языков
#!/usr/bin/env python3

Недостатки

  1. Предполагается наличие /usr/bin/env
  • Он присутствует практически во всех современных Unix/Линукс системах, но в очень специфических средах может отсутствовать.
  1. В зависимости от PATH может быть выбран другой интерпретатор
  • Если настройка PATH нарушена или неожиданная версия bash находится раньше в PATH, может быть выполнена нежелательная версия.
  1. Иногда требует осторожности с точки зрения безопасности
  • В очень чувствительных к безопасности средах предпочтение отдается абсолютным путям, а не поиску интерпретатора на основе PATH.

5. Сравнение двух подходов

Представим краткую сравнительную таблицу:

Критерий #!/bin/bash #!/usr/bin/env bash
Метод указания пути к интерпретатору Фиксированный абсолютный путь PATH через поиск
Портативность (совместимость с разными системами) Низкая (ломается при изменении пути) Высокая (достаточно, чтобы bash был в PATH)
Какая версия bash используется Всегда /bin/bash Первая найденная bash в PATH
Гарантия нужной версии Относительно легко Может меняться в зависимости от состояния PATH
Безопасность/Контроль Выше (фиксированный путь) Немного ниже (зависит от PATH)
Современные тенденции Относительно устаревший стиль В последнее время чаще рекомендуется

6. Когда что использовать?

"В итоге, что мне использовать?" — ответим на этот вопрос, разобрав ситуации.

1) Скрипты для личного или командного использования (типичная среда разработки)

  • В основном рекомендуется следующее:
#!/usr/bin/env bash
  • Причина:

  • В серверах, локальных средах, CI-средах, управляемых разработчиками, расположение bash может отличаться.

  • Поиск и выполнение на основе PATH более гибок, и современные инструменты/скрипты предпочитают этот подход.

2) Операционные скрипты, строго соответствующие конкретной серверной среде

  • Например, если на всех серверах компании bash установлен по общему пути /bin/bash,

  • И среда сервера достаточно статична:

#!/bin/bash
  • Причина:

  • Гарантирует использование всегда одного и того же интерпретатора.

  • Помогает избежать непредвиденного поведения, вызванного изменениями PATH.

3) Если вы хотите сделать скрипт максимально переносимым?

  • Если вы предполагаете среду, где "bash может вообще отсутствовать", то стоит задуматься, действительно ли скрипт должен зависеть от bash.

  • Если возможно, пишите на sh:

#!/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 myscript.sh
python3 myscript.py
  • Однако, если вы хотите запустить скрипт следующим образом, shebang обязателен.
./myscript.sh
./myscript.py
  • Особенно, если это "утилитарный" скрипт, предназначенный для использования другими, 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