Поскольку файл не относится ни к одному из типов исполняемых файлов, распознаваемых системой, и при условии, что у вас есть разрешение на выполнение этого файла, системный вызов execve()
обычно завершается ошибкой сENOEXEC
(не исполняемым файлом.)ошибка.
Дальнейшие действия зависят от приложения и/или библиотечной функции, используемой для выполнения команды.
Это может быть, например, оболочка, функция execlp()
/ execvp()
libc.
Большинство других приложений будут использовать любой из них при выполнении команды. Они будут вызывать оболочку, например, с помощью функции system("command line")
libc, которая обычно вызывает sh
для анализа этой командной строки (, путь которой можно определить во время компиляции (, например /bin/sh
vs /usr/xpg4/bin/sh
в Solaris ))или вызовите оболочку, хранящуюся в $SHELL
, сами по себе, например vi
с ее командой !
, или xterm -e 'command line'
и многие другие команды(su user -c
вызовут оболочку входа пользователя вместо $SHELL
).
Как правило, -менее текстовый файл, который не начинается с #
, считается сценарием sh
. Однако sh
будет варьироваться.
execlp()
/ execvp()
, при возврате execve()
ENOEXEC
обычно вызывает sh
. Для систем, которые имеют более одного sh
, так как они могут соответствовать более чем одному стандарту, какой sh
он будет, как правило, определяется во время компиляции (приложения с использованием execvp()
/ execlp()
путем связывания другой блок кода, который ссылается на другой путь кsh
). Например, в Solaris это будет либо/usr/xpg4/bin/sh
(стандарт, POSIX sh
), либо/bin/sh
(оболочка Bourne (устаревшая оболочка )в Solaris 10 и старше, ksh93 в Solaris 11 ).
Когда дело доходит до оболочек, существует множество вариантов. bash
, AT&T ksh
, оболочка Борна обычно сама интерпретирует сценарий (в дочернем процессе, если exec
не используется )после имитации execve()
, которая сбрасывает все неэкспортированные переменные,закрыл все закрытия -на -exec fds, удалил все пользовательские ловушки, псевдонимы, функции...(bash
будет интерпретировать скрипт в режиме sh
). yash
будет выполнять сам (с sh
как argv[0]
, поэтому в режиме sh
)интерпретировать его.
zsh
, pdksh
,ash
-обычно вызывают sh
(, путь к которым определяется во время компиляции ).
Для csh
иtcsh
(и sh
некоторых ранних BSD ), если первым символом файла является #
, то они будут выполняться для его интерпретации, и sh
в противном случае. Это восходит к временам до -shebang, когда csh
действительно распознавал #
как комментарии, но не оболочку Bourne, поэтому #
был намеком на то, что это был скрипт csh.
fish
(по крайней мере, версия 2.4.0 ), просто возвращает ошибку, если execve()
сбой (он не пытается рассматривать это как сценарий ).
Некоторые оболочки (, такие как bash
или AT&T ksh
), сначала пытаются эвристически определить, предназначен ли файл для сценария или нет. Таким образом, вы можете обнаружить, что некоторые оболочки отказываются выполнять сценарий, если он содержит символ NUL в первых нескольких байтах.
Также обратите внимание, что если execve()
не работает с ENOEXEC, но в файле есть строка shebang, некоторые оболочки пытаются интерпретировать эту строку самостоятельно.
Итак, несколько примеров:
$SHELL
равно /bin/bash
, xterm -e 'myscript with args'
будет интерпретироваться myscript
как bash
в режиме sh
. В то время как с xterm -e myscript with args
xterm
будет использовать execvp()
, поэтому сценарий будет интерпретироваться sh
. su -c myscript
в Solaris 10, где root
оболочка входа в систему — /bin/sh
, а /bin/sh
— оболочка Bourne, интерпретируется оболочкой Bourne myscript
. /usr/xpg4/bin/awk 'BEGIN{system("myscript")'
на Solaris 10 будет интерпретироваться как/usr/xpg4/bin/sh
(то же самое для/usr/xpg4/bin/env myscript
). find. -prune -exec myscript {} \;
на Solaris 10 (с использованиемexecvp()
)будет интерпретироваться /bin/sh
даже с /usr/xpg4/bin/find
,даже в среде POSIX (ошибка соответствия ). csh -c myscript
будет интерпретирован csh
, если он начинается с #
, и с sh
в противном случае. В общем, вы не можете быть уверены, какая оболочка будет использоваться для интерпретации этого скрипта, если вы не знаете, как и чем он будет вызываться.
В любом случае, read -p
— этоbash
-только синтаксис, поэтому вам нужно убедиться, что скрипт интерпретируетсяbash
(и избегать вводящего в заблуждение .sh
расширения ). Либо вы знаете путь к исполняемому файлу bash
и используете:
#! /path/to/bash -
read -p...
Или вы можете попробовать и полагаться на $PATH
поиск bash
исполняемого файла (, предполагая, что bash
установлен ), используя:
#! /usr/bin/env bash
read -p...
(env
почти повсеместно встречается в /usr/bin
). Кроме того, вы можете сделать его совместимым с POSIX+Bourne, и в этом случае вы можете использовать /bin/sh
. Все системы будут иметь /bin/sh
. На большинстве из них он будет (по большей части )POSIX -совместимым, но вы все равно можете найти там время от времени оболочку Bourne.
#! /bin/sh -
printf >&2 'Enter a user name: '
read user
printf '%s\n' "$user"
Когда у вас нет#!
(называемой shebang)строки, используется sh . Чтобы проверить это, вы можете запустить следующий скрипт.
ps -p $$
echo -n "The real shell is: "
realpath /proc/$$/exe
На моем компьютере я получаю
PID TTY TIME CMD
13718 pts/16 00:00:00 sh
The real shell is: /usr/bin/bash
даже если моя оболочка по умолчанию zsh . Он использует bash , так как на моей машине команда sh реализована с помощью bash .