19

Я только начал глубже разбираться в сценариях оболочки, и я всегда просто бросал свой сценарий в файл, отмечал его как chmod +x а затем делал /path/to/script.sh и позволял любому интерпретатору по умолчанию иметь свой путь с ним, который я предположил, был zsh, потому что это то, что я использовал для моей оболочки. По-видимому, кажется, что это просто /bin/sh по умолчанию, даже если я запускаю сценарий из приглашения zsh, потому что я начал вставлять специфичные для zsh вещи в свои сценарии, и он не работает, если я не запускаю zsh /path/to/script.sh ,

Чтобы перейти к сути, вот мои вопросы:

  1. Какая оболочка выполняет сценарии, когда нет строки shebang (#!/path/to/shell) в начале? Я предполагаю /bin/sh но я не могу подтвердить.
  2. Что считается "наилучшей практикой" с точки зрения написания сценариев оболочки, которые будут работать на любой платформе? (хорошо, это своего рода открытый)
  3. Можно ли написать скрипт, который пытается использовать zsh и возвращается к bash, если zsh недоступен? Я попытался поместить две строки shebang, как показано ниже, но это просто ошибки с bad interpreter: /bin/zsh: no such file or directory , если я попробую его на машине без zsh.

    #!/bin/zsh

    #!/bin/bash

2 ответа2

25

Какая оболочка выполняет сценарии, когда нет строки shebang (#!/ путь / к / оболочка) в начале? Я предполагаю / bin / sh, но я не могу подтвердить.

Ядро отказывается выполнять такие сценарии и возвращает ENOEXEC, поэтому точное поведение зависит от программы , вы запускаете такой скрипт с.

  • Баш 4.2.39 - использует себя
  • busybox-ash 1.20.2 - использует себя
  • тире 0,5,7 - пробеги / бин / ш
  • fish 1.23.1 - жалуется на ENOEXEC, затем обвиняет не тот файл
  • AT & T ksh 93u+2012.08.01 - использует себя
  • мкш R40f - работает / бин / ш
  • 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 - смешно смотрится на вас.

В glibc функции execv() или execve() просто возвращают ENOEXEC. Но execvp() скрывает этот код ошибки и автоматически вызывает /bin /sh. (Это задокументировано в exec (3p).)

Что считается "наилучшей практикой" с точки зрения написания сценариев оболочки, которые будут работать на любой платформе? (хорошо, это своего рода открытый)

Либо придерживайтесь sh и только POSIX-определенных функций, либо просто используйте полную версию bash (которая широко доступна) и укажите ее в своих требованиях при распространении.

(Теперь, когда я думаю об этом, Perl - или, возможно, Python - будет еще более переносимым, не говоря уже о лучшем синтаксисе.)

Всегда добавляйте строку Шебанга. Если вы используете bash или zsh, используйте #!/usr/bin/env bash вместо жесткого кодирования пути оболочки. (Однако оболочка POSIX гарантированно находится в /bin/sh , поэтому в этом случае пропустите env .)

(К сожалению, даже /bin/sh не всегда одинаков. Программа GNU autoconf имеет дело с множеством разных странностей.)

Можно ли написать скрипт, который пытается использовать zsh и возвращается к bash, если zsh недоступен? Я попытался поместить две строки shebang, как показано ниже, но это просто ошибки с плохим интерпретатором: /bin /zsh: нет такого файла или каталога , если я попробую его на машине без zsh.

Может быть только одна линия Шебанга; все, что находится после символа новой строки, даже не читается ядром, а интерпретируется оболочкой как комментарий.

Можно написать скрипт, который запускается как #!/bin/sh проверяет, какая оболочка доступна, и запускает exec zsh "$0" "$@" или exec bash "$0" "$@" зависимости от результата. Однако синтаксис, используемый bash и zsh, настолько различен в разных местах, что я бы не советовал делать это для вашего же здравомыслия.

2

1) текущая оболочка, в которой вы работаете.

2) Придерживайтесь того же типа оболочки (bash/dash/ash/csh/ независимо от вашего вкуса) и убедитесь, что ваши "поддерживаемые платформы" устанавливают оболочку, которую вы хотите использовать по умолчанию. Также попробуйте использовать общедоступные команды в системах. Избегайте машинно-специфических опций.

3) На самом деле в interpreter directive логики «если-то-еще». Вы должны указать оболочку, которая должна существовать во всех системах, которые вы хотите поддерживать ... то есть #!/bin/bash или укажите общий #!/bin/sh если ваш сценарий достаточно универсален для всех оболочек.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .