Я только начал углубляться в скрипты оболочки, и я всегда просто закидывал свой скрипт в файл, помечал его, chmod +x
а затем делал /path/to/script.sh
так, как хочет интерпретатор по умолчанию, которым я считал zsh, потому что я использовал его для своей оболочки. По-видимому, это просто /bin/sh
по умолчанию, даже если я запускаю скрипт из командной строки zsh, потому что я начал добавлять специфичные для zsh вещи в свои скрипты, и они не работают, пока я не запущу zsh /path/to/script.sh
.
Чтобы перейти к сути, вот мои вопросы:
#!/path/to/shell
Какая оболочка выполняет скрипты, если в начале нет строки shebang ( )? Я предполагаю/bin/sh
, но не могу подтвердить.- Что считается «лучшими практиками» с точки зрения написания сценариев оболочки, которые будут работать на любой платформе? (ладно, это своего рода открытый вопрос)
Можно ли написать скрипт, который пытается использовать zsh и возвращается к bash, если zsh недоступен? Я пробовал вставлять две строки shebang, как показано ниже, но он просто выдает ошибки,
bad interpreter: /bin/zsh: no such file or directory
если я пробую его на машине без zsh.#!/bin/zsh
#!/bin/bash
решение1
Какая оболочка выполняет скрипты, если в начале нет строки shebang (#!/path/to/shell)? Я предполагаю /bin/sh, но не могу подтвердить.
Ядро отказывается выполнять такие скрипты и возвращает ENOEXEC, поэтому точное поведение зависит от программы, в которой вы запускаете такой скрипт.от.
- bash 4.2.39 – использует сам себя
- busybox-ash 1.20.2 – использует сам себя
- dash 0.5.7 – запускает /bin/sh
- fish 1.23.1 – жалуется на ENOEXEC, а затем винит не тот файл
- AT&T ksh 93u+2012.08.01 – использует сам себя
- mksh R40f – запускает /bin/sh
- pdksh 5.2.14 – запускает /bin/sh
- sh-heirloom 050706 – использует себя
- tcsh 6.18.01 – запускает /bin/sh
- zsh 5.0.0 – запускает /bin/sh
- cmd.exe 5.1.2600 – смотрит на тебя странно.
Вглибк, функции execv()
или execve()
просто возвращают ENOEXEC. Но execvp()
скрывает этот код ошибки и автоматически вызывает /bin/sh. (Это задокументировано висполнитель(3п).)
Что считается «лучшими практиками» с точки зрения написания сценариев оболочки, которые будут работать на любой платформе? (ладно, это своего рода открытый вопрос)
Либо придерживайтесь sh
только определенных POSIX функций, либо просто используйте полныйБаш(который широко доступен) и укажите это в своих требованиях, если вы его распространяете.
(Теперь, когда я об этом думаю, Perl — или, возможно, Python — был бы еще более переносимым, не говоря уже о лучшем синтаксисе.)
Всегдадобавьте строку shebang. Если вы используете bash или zsh, используйте #!/usr/bin/env bash
вместо жесткого кодирования путь к оболочке. (Однако оболочка POSIX гарантированно находится в /bin/sh
, поэтому в этом случае пропустите env
.)
(К сожалению, даже /bin/sh
не всегда одно и то же. GNUавтоконфпрограмма должна иметь дело смного разных причуд.)
Можно ли написать скрипт, который пытается использовать zsh и возвращается к bash, если zsh недоступен? Я пробовал вставить две строки shebang, как показано ниже, но он просто выдает ошибки сплохой интерпретатор: /bin/zsh: нет такого файла или каталогаесли я попробую это на машине без zsh.
Строка shebang может быть только одна; все, что находится после символа новой строки, ядром даже не читается и воспринимается оболочками как комментарий.
Еговозможныйнаписать скрипт, который запускается как #!/bin/sh
, проверяет, какая оболочка доступна, и запускает exec zsh "$0" "$@"
или exec bash "$0" "$@"
в зависимости от результата. Однако синтаксис, используемый bash и zsh, настолько отличается в разных местах, что я быне рекомендую этого делатьдля вашего собственного рассудка.
решение2
1) Текущая оболочка, в которой вы работаете. (какая бы она ни была)
2) Придерживайтесь одного и того же типа оболочки (bash/dash/ash/csh/какая вам нравится) и убедитесь, что ваши «поддерживаемые платформы» устанавливают оболочку, которую вы хотите использовать по умолчанию. Также старайтесь использовать общедоступные команды в системах. Избегайте машинно-специфичных опций.
3) На самом деле в . нет логики "если-то-иначе" interpreter directive
. Вам следует указать оболочку, которая должна существовать во всех системах, которые вы хотите поддерживать... т. е. #!/bin/bash
или указать универсальную, #!/bin/sh
если ваш скрипт достаточно универсален для всех оболочек.