Поскольку файл не относится ни к одному из типов исполняемых файлов, распознаваемых системой, и при условии, что у вас есть разрешение на выполнение этого файла, execve()системный вызов обычно завершается с ошибкой ENOEXEC( не исполняемой ).
То, что происходит затем, зависит от приложения и / или библиотечной функции, используемой для выполнения команды.
Это может быть, например, оболочка execlp()/execvp() функция libc.
Большинство других приложений будут использовать любое из них при запуске команды. Они будут вызывать оболочку, например, с помощью system("command line")функции libc, которая обычно вызывает shсинтаксический анализ этой командной строки (путь которой может быть определен во время компиляции (как /bin/shvs /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).
Когда дело доходит до раковин, есть много вариаций. bashAT & 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()неудачи (она не пытается рассматривать ее как скрипт).
Некоторые оболочки (например, bashAT & 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"