Поскольку файл не относится ни к одному из типов исполняемых файлов, распознаваемых системой, и при условии, что у вас есть разрешение на выполнение этого файла, 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
, оболочка Bourne обычно интерпретирует скрипт (в дочернем процессе, если он exec
не используется) после того, как имитировал execve()
, который сбрасывает все неэкспортированные переменные, закрывает все fd-команды close-on-exec, удаляет все пользовательские ловушки, псевдонимы, функции ... ( bash
будет интерпретировать скрипт в sh
режиме). yash
выполнит себя ( sh
как argv[0]
в sh
режиме), чтобы интерпретировать его.
zsh
, pdksh
, ash
-А оболочка обычно вызывается sh
(путь которого определяется во время компиляции).
Для csh
и tcsh
(и sh
некоторых ранних BSD), если первым символом файла является #
, то они выполнятся сами для его интерпретации, и в sh
противном случае. Это восходит к периоду до Шебанга, когда csh
он распознавал #
как комментарии, но не оболочку Bourne, так что #
был намек на то, что это был скрипт csh.
fish
(по крайней мере, версия 2.4.0), просто возвращает ошибку в случае execve()
неудачи (она не пытается рассматривать ее как скрипт).
Некоторые оболочки (например, bash
AT & T ksh
) сначала пытаются эвристически определить, должен ли файл быть сценарием или нет. Таким образом, вы можете обнаружить, что некоторые оболочки отказываются выполнять скрипт, если в первых нескольких байтах он имеет символ NUL.
Также обратите внимание, что если execve()
ENOEXEC завершается неудачно, но файл имеет строку shebang, некоторые оболочки пытаются интерпретировать эту строку 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, будет myscript
интерпретироваться оболочкой Bourne.
/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"