Предположим, что оболочкой по умолчанию для моей учетной записи является zsh, но я открыл терминал, запустил bash и выполнил скрипт с именем prac002.sh
, какой интерпретатор оболочки будет использоваться для выполнения сценария, zsh или bash? Рассмотрим следующий пример:
papagolf@Sierra ~/My Files/My Programs/Learning/Shell % sudo cat /etc/passwd | grep papagolf
[sudo] password for papagolf:
papagolf:x:1000:1001:Rex,,,:/home/papagolf:/usr/bin/zsh
# papagolf's default shell is zsh
papagolf@Sierra ~/My Files/My Programs/Learning/Shell % bash
# I fired up bash. (See that '%' prompt in zsh changes to '$' prompt, indicating bash.)
papagolf@Sierra:~/My Files/My Programs/Learning/Shell$ ./prac002.sh
Enter username : Rex
Rex
# Which interpreter did it just use?
** РЕДАКТИРОВАТЬ: ** Вот содержание сценария
papagolf@Sierra ~/My Files/My Programs/Learning/Shell % cat ./prac002.sh
read -p "Enter username : " uname
echo $uname
. prac002.sh
предположении, что ваш скрипт находится в текущем каталоге.. ./prac002.sh
и он будет работать с текущей оболочкой, то есть с точкой (.
), пробелом () и путем к вашему сценарию. Это называется дотсорсинг вашего сценария. ;-)Ответы:
Поскольку скрипт не начинается со
#!
строки shebang, указывающей, какой интерпретатор использовать, POSIX говорит, что :Это выражение немного двусмысленно, и разные оболочки имеют разные интерпретации.
В таком случае, Bash запустит скрипт, используя сам себя . С другой стороны, если вы запустите его из zsh, zsh будет использовать
sh
(что бы это ни было в вашей системе).Вы можете проверить это поведение для этого случая, добавив эти строки в скрипт:
Вы заметите, что из Bash первая строка выводит вашу версию, а вторая никогда ничего не говорит, независимо от того, какую оболочку вы используете.
/bin/sh
, скажем, вашdash
, то ни одна строка не будет ничего выводить, когда скрипт выполняется из zsh или dash./bin/sh
ссылка на Bash, вы увидите вывод первой строки во всех случаях./bin/sh
это другая версия Баша , чем вы использовали напрямую, вы увидите другой вывод при запуске сценария из Баш непосредственно и от Zsh.Команда
ps -p $$
из ответа rools также покажет полезную информацию о команде, используемой оболочкой для выполнения скрипта.источник
execl()
вызова, когда сценарий оболочки не содержит шебанга и выполняется какscriptname
? Разве это не происходит, когда скрипт оболочки выполняется какbash scriptname
? Разве это не происходит, когда скрипт оболочки содержит шебанг и выполняется какscriptname
?Поскольку файл не относится ни к одному из типов исполняемых файлов, распознаваемых системой, и при условии, что у вас есть разрешение на выполнение этого файла,
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
(стандарт, POSIXsh
) или/bin/sh
(оболочка Bourne (устаревшая оболочка) в Solaris 10 и старше, ksh93 в Solaris 11).Когда дело доходит до раковин, есть много вариаций.
bash
AT & Tksh
, оболочка 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 & Tksh
) сначала пытаются эвристически определить, должен ли файл быть сценарием или нет. Таким образом, вы можете обнаружить, что некоторые оболочки отказываются выполнять скрипт, если в первых нескольких байтах он имеет символ 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
поиска вbash
исполняемый файл (при условииbash
установки) с помощью:(
env
почти повсеместно встречается в/usr/bin
). Кроме того, вы можете сделать его совместимым с POSIX + Bourne, в этом случае вы можете использовать/bin/sh
. Все системы будут иметь/bin/sh
. На большинстве из них он будет (по большей части) POSIX-совместимым, но вы все равно можете найти там и сейчас оболочку Bourne.источник
Если у вас нет какой-либо
#!
(называемой шебанг ) строки, используется sh . Чтобы проверить это, вы можете запустить следующий скрипт.На моем компьютере я получаю
даже если моя оболочка по умолчанию - zsh . Он использует bash, поскольку на моей машине команда sh реализована с помощью bash .
источник