Запуск сценария оболочки, когда «/ bin / sh» указывает на «/ bin / bash»

11

Я прочитал следующее в этом вопросе :

bash поддерживает ключ --posix, что делает его более совместимым с POSIX. Он также пытается имитировать POSIX, если вызывается как sh .

Выше цитата предполагает, что /bin/shэто ссылка, на которую указывает /bin/bash.

Но я не совсем понимаю, что подразумевается под словом «вызывается как sh» .


Скажем, у меня есть следующий скрипт, который называется "script.sh":

#!/bin/bash
echo "Hello World"

Пожалуйста, скажите мне в каждом из следующих случаев, будет ли скрипт выполняться в обычном bashрежиме или в режиме POSIX (предположим, что я выполнил следующие команды в работающем терминале bash):

  1. sh script.sh
  2. bash script.sh
  3. ./script.sh

Теперь скажите, что у меня есть следующий скрипт, который называется «script.sh» (который похож на скрипт выше, но без шебанга):

echo "Hello World"

Пожалуйста, скажите мне в каждом из следующих случаев, будет ли скрипт выполняться в обычном bashрежиме или в режиме POSIX (предположим, что я выполнил следующие команды в работающем терминале bash):

  1. sh script2.sh
  2. bash script2.sh
  3. ./script2.sh
user269904
источник
stackoverflow.com/questions/5725296/…
Джордж Василиу

Ответы:

19

Только случаи 1 и 4 будут работать в режиме POSIX (при условии, что shэто bash, а не какая-то другая реализация sh). Любой случай, который явно вызывает bashбез --posixволи не будет, будь то Шебанг или нет. Любой случай, который явно вызывает, shбудет. Шебанг используется только тогда, когда для сценария уже явно не запущена оболочка.

Случай 6, если ваш терминал работает bash, не будет работать в режиме POSIX, и Bash вызовет его, используя себя. Если ваш терминал был запущен ЗШ вместо этого, случай 6 будет также работать в режиме POSIX. POSIX неоднозначно относится именно к тому, что должно произойти в этом случае , и Bash и zsh сделали там разные выборы. Bash вызывает скрипт используя себя, а zsh использует sh(что бы это ни было). Другие оболочки также различаются по этому вопросу.


Один простой способ узнать, в каком режиме вы находитесь - создать тело скрипта:

kill -SIGHUP

которая завершится с ошибкой в ​​режиме POSIX , но даст инструкции по использованию за ее killпределами. Это простое различие, и оно работает через широкий диапазон версий Bash, начиная с того, с чем вы, вероятно, столкнетесь.

Майкл Гомер
источник
3
Есть другие вещи, которые заставят bashработать в режиме POSIX, такие как POSIXLY_CORRECTпеременная окружения или SHELLOPTS=posix.
Стефан Шазелас
1
[ -o posix ]это более очевидный способ проверить, что вы работаете в режиме posix в bash (не в других оболочках (кроме yash), поэтому вы не захотите делать это в shскрипте). POSIXLY_CORRECT=1 bash -c '[ -o posix ] && echo yes'выводит yes`
Стефан Шазелас
2
В случае 6 bash вызывает сценарий вместе с самим собой в режиме POSIX, когда он сам находится в режиме POSIX, как того требует POSIX. POSIX не определяет механизм she-bang, и 6 - единственный способ POSIX иметь исполняемые сценарии, и он четко указан (в средах POSIX сценарий должен интерпретироваться совместимой утилитой sh).
Стефан Шазелас
8

«Вызывается как» относится к тому , что это то , что процесс запуска Bash ставит в своей «нулевой» аргумент командной строки, argv[0].

Когда программа запускается с exec*()системными вызовами , они на самом деле не узнают имя двоичного файла, содержащего программу, но вместо этого вызывающий процесс может свободно поместить туда все, что захочет. Обычно, конечно, имя берется из файловой системы, так что если вы запустите /bin/sh, это то, что там будет помещено. И если /bin/shэто Bash, это не должна быть символическая ссылка, это может быть жесткая ссылка или просто еще одна копия программы оболочки.

В качестве примера установки «имени программы» execкоманда Bash может установить нулевой аргумент с -aпараметром. (Мы можем сделать то же самое с Perl или напрямую с C и т. Д.)

Вот mynameпростая C-программа, которая просто печатает свой нулевой аргумент, имя, которое она видит сама:

$ ./myname 
I am ./myname
$ (exec -a something ./myname )
I am something
$ mv ./myname somename
$ ln -s somename othername
$ ./somename 
I am ./somename
$ ./othername
I am ./othername

Источник:

#include <stdio.h>
int main(int argc, char *argv[]) {
    printf("I am %s\n", argv[0]);
    return 0;
}

Но, чтобы ответить на пронумерованные вопросы ...

(1 и 4) бег sh somescriptбудет работать, что shна вас PATH, вероятно, /bin/shно, возможно, что-то вроде/usr/xpg4/bin/sh .

  • Если это Bash, он работает в режиме POSIX, так как видит имя sh.
  • Если это оболочка Z или оболочка Korn, она также видит имя sh, но работает в режиме «SH-совместимости», который нацелен на совместимость с оболочкой Bourne и слегка отличается от режима полного соответствия POSIX в обеих этих оболочках. ,
  • Это может быть оболочка Альмквиста, настоящая оболочка Борна или что-то еще, конечно.

(2 и 5) Запуск bash somescriptбудет выполняться в обычном режиме Bash (опять же, это, конечно, зависит от того, что bashу вас PATHесть.)

(3) Здесь имя сценария присваивается непосредственно системному вызову вместо файла программы. Ядро читает строку hashbang и использует ее для запуска скрипта.

(6) Это сложный. Это похоже на (3), но системный вызов для запуска программы завершается с ошибкой ( ENOEXEC (Exec format error)), так как нет строки hashbang. Что произойдет дальше , зависит от того , является ли оболочка , что вы работаете на себя в режиме POSIX. POSIX требует, чтобы POSIX-совместимая оболочка вела себя особым образом в ответ на ENOEXEC. Однако в «команде, эквивалентной вызову оболочки», есть некоторая свобода действий, которая означает, что разные оболочки делают разные вещи.

  • Оболочка Bourne Again повторно запускает себя в том же режиме, в котором имя сценария используется в качестве первого аргумента командной строки. В своем режиме, соответствующем POSIX, он, конечно же, работает в режиме, соответствующем POSIX, тем самым подчиняясь требованию POSIX для вызова оболочки, соответствующей POSIX.
  • Оболочка Z, оболочка Almquist и оболочка Korn запускаются /bin/shс именем сценария, вставленным перед остальными аргументами в качестве первого аргумента командной строки. Оболочка Z, оболочка Almquist и оболочка Korn (пытаются) вызвать POSIX-совместимую оболочку, предполагая, что /bin/shпрограмма одна.
ilkkachu
источник
Не могли бы вы поделиться исходным кодом этой программы на C ..
GypsyCosmonaut
int main(int argc, char *argv[]){printf("I am %s\n",argv[0]);}
Стиг Хеммер
Вот и все.
ilkkachu
4

Выполняемая оболочка - это либо вызываемая в командной строке, либо оболочка в shebang (если в командной строке это не указано).

Итак, версии 1 и 4 будут работать с sh, 2 и 5 с bash, а 6 может не работать, если вы используете sh (и некоторые другие) в интерактивном режиме. Bash запускает скрипт. Кш тоже. Зш начинает это как ш.

Только те, кто запущен как, shбудут использовать опцию posix, если bash связан с /bin/sh.

Добавьте эту строку в ваш скрипт, чтобы определить, работает ли какая-либо версия bash ksh или zsh:

echo "Hello World $BASH_VERSION $KSH_VERSION $ZSH_VERSION"
NotAnUnixNazi
источник