Немного про shebang в Linux

Немного про shebang в Linux

Shebang — это последовательность #! в начале исполняемого файла, которая указывает системе, какая программа должна интерпретировать этот скрипт📝. Популярным шебангом для bash является #!/bin/bash. Его особенность в том, что он жёстко указывает на конкретный путь в файловой системе: /bin/bash. Это справедливо, если вы точно знаете, что bash действительно находится по этому пути🛣️.

Всё бы ничего, но есть нюансы🤷‍♂️. Первый - в большинстве Linux дистрибутивов bash установлен в /usr/bin/bash, что уже может завершить ваш скрипт ошибкой. Чтобы этого избежать, в системе создают символьную ссылку /bin, указывающую на директорию /usr/bin:

BASH
ls -ld /bin
Нажмите, чтобы развернуть и увидеть больше
PLAINTEXT
Permissions Size User Group Date Modified    Name
lrwxrwxrwx     7 root root  2023-09-22 19:26 /bin -> usr/bin
Нажмите, чтобы развернуть и увидеть больше

Вывод напрашивается сам собой: в качестве shebang указывать /usr/bin/bash, но и это не является универсальным решением🤔. В некоторых дистрибутивах бинарник bash может все таки находиться в другом месте.

Поэтому часто в качестве shebang используют #!/usr/bin/env bash💡.

env - утилита для работы с переменными окружения. В случае с bash утилита env перед запуском ищет бинарник в переменной $PATH, которая содержит список директорий с исполняемыми файлами, разделённых символом :. Например:

BASH
/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
Нажмите, чтобы развернуть и увидеть больше

Такой вариант шебанга является более универсальным: если bash установлен в нестандартном месте, но доступен через PATH, он будет найден.
Данное поведение одинаково в Linux, macOS, BSD и виртуальных окружениях😌.

Но есть и недостатки😠. Данный способ запуска чуть менее эффективен (есть лишний вызов env), и в редких ситуациях может запуститься «не тот» bash, если в PATH находятся разные его версии. Например, есть два разных баша: /usr/local/bin/bash и /usr/bin/bash. В случае PATH, указанного выше, будет использован /usr/local/bin/bash.

Увидеть разницу в работе шебангов можно с помощью инструмента отслеживания системных вызовов strace, он же “страус”🐓.

Создадим два скрипта и сделаем их исполняемыми:

BASH
cat > test-bin.sh <<EOF
#!/bin/bash
echo "I am /bin/bash"
EOF

cat > test-env.sh <<EOF
#!/usr/bin/env bash
echo "I am env bash"
EOF

chmod +x test-bin.sh test-env.sh
Нажмите, чтобы развернуть и увидеть больше

Запускаем первый с помощью страуса и фильтруем вывод по вызову execve:

BASH
strace -f -e trace=execve -s 200 ./test-bin.sh
Нажмите, чтобы развернуть и увидеть больше

Видим лишь один вызов:

PLAINTEXT
execve("./test-bin.sh", ["./test-bin.sh"], 0x7ffe817c2458 /* 37 vars */) = 0
I am /bin/bash
+++ exited with 0 +++
Нажмите, чтобы развернуть и увидеть больше

Теперь запустим вариант с env:

BASH
strace -f -e trace=execve -s 200 ./test-env.sh
Нажмите, чтобы развернуть и увидеть больше

Тут вывод будет заметно длиннее. Видно, что происходит поиск исполняемого файла в нескольких директориях:

PLAINTEXT
strace -f -e trace=execve -s 200 ./test-env.sh 2>&1
execve("./test-env.sh", ["./test-env.sh"], 0x7ffd9fe2e898 /* 37 vars */) = 0
execve("/usr/local/sbin/bash", ["bash", "./test-env.sh"], 0x7ffcaca77068 /* 37 vars */) = -1 ENOENT (No such file or directory)
execve("/usr/local/bin/bash", ["bash", "./test-env.sh"], 0x7ffcaca77068 /* 37 vars */) = -1 ENOENT (No such file or directory)
execve("/usr/sbin/bash", ["bash", "./test-env.sh"], 0x7ffcaca77068 /* 37 vars */) = -1 ENOENT (No such file or directory)
execve("/usr/bin/bash", ["bash", "./test-env.sh"], 0x7ffcaca77068 /* 37 vars */) = 0
I am env bash
+++ exited with 0 +++
Нажмите, чтобы развернуть и увидеть больше

Любопытно, что порядок поиска не полностью соответствует очерёдности директорий в PATH. Чередуясь проверяются *sbin, затем *bin🤔.

Тем не менее, рекомендуется использовать именно #!/usr/bin/env bash для большей универсальности👍.
Стоит отметить, что подобный подход справедлив для любых интерпретаторов, например #!/usr/bin/env python#!/usr/bin/env awk и т.д.

Авторские права

Автор: Иван Чёрный

Ссылка: https://r4ven.ru/shell/nemnogo-pro-shebang-v-linux/

Лицензия: CC BY-NC-SA 4.0

Использование материалов блога разрешается при условии: указания авторства/источника, некоммерческого использования и сохранения лицензии.

Начать поиск

Введите ключевые слова для поиска статей

↑↓
ESC
⌘K Горячая клавиша