Написание сценариев оболочки, которые будут работать в любой оболочке (используя несколько строк shebang?)

19

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

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

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

    #!/bin/zsh

    #!/bin/bash

swrobel
источник

Ответы:

26

Какая оболочка выполняет сценарии, когда в начале нет строки shebang (#! / Path / to / shell)? Я предполагаю / 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, настолько различен в разных местах, что я бы не советовал делать это для вашего же здравомыслия.

grawity
источник
1
как вы отследили, что на самом деле вызывал каждая оболочка, когда получал ENOEXEC?
Swrobel
2
@SWrobel: Использование strace -f -e fork,clone,execve. Некоторые снаряды продолжали исполняться /bin/shпосле неудачи; другие интерпретировали сценарий сами.
Гравитация
1
@SWrobel: Другой метод - запустить скрипт, состоящий из readlink /proc/$$/exe.
Гравитация
2
Смотрите также ответ Stéphane Chazelas в к переводчику , какая оболочка запускает скрипт с не притоном? (межсайтовая
G-Man говорит: «Восстановите Монику»
1
Для cshи tcshповедение зависит от того, начинается ли сценарий #(в этом случае они вызывают себя вместо sh для интерпретации сценария). Это восходит к тому времени, когда csh поддерживал комментарии, но не оболочку Bourne, поэтому #намек на то, что это был csh-скрипт.
СЧ
2

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

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

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

TheCompWiz
источник