Как я чувствую, это ошибка. Ниже какая-то "детективная история".
Да, в коде exec.def
мы видим:
if (subshell_environment || (interactive == 0 && no_exit_on_failed_exec == 0))
exit_shell (exit_value);
Таким образом, exec
будет вызывать выход из оболочки a) в неинтерактивной оболочке с false
"no_exit_on_failed_exec" b) при запуске exec
в subshell
Для интерактивной оболочки, если команда существует, оболочка заменяется вызванной командой:
Exec
Эта встроенная оболочка заменяет текущий процесс указанной командой. Обычно, когда оболочка встречает команду, она запускает дочерний процесс, чтобы фактически выполнить команду.
Используя встроенную функцию exec, оболочка не разветвляется, а команда exec'ed заменяет оболочку.
Поэтому при использовании в сценарии он вызывает выход из сценария, когда завершается команда exec.
Пример 15-24. Эффекты exec
#!/bin/bash
exec echo "Exiting \"$0\" at line $LINENO." # Exit from script here.
# $LINENO is an internal Bash variable set to the line number it's on.
**# The following lines never execute.**
http://www.tldp.org/LDP/abs/html/internal.html#EXECREF
source
команда не вызывает subshell - она заставляет все команды выполняться в текущей активной оболочке (она используется, например, для установки переменных - не для некоторой подоболочки, которая завершится, а для текущей оболочки). Таким образом, после выполнения команды как с source
и непосредственно в оболочке, ваша оболочка прекратит работу (это ожидаемое поведение).
Когда скрипт запускается с использованием `source ', он запускается в существующей оболочке, любые переменные, созданные или измененные скриптом, останутся доступными после его завершения.
http://ss64.com/bash/source.html
Я скомпилировал bash-4.2
и запустил его в отладчике gdb
.
Это последние команды, которые выполняются перед выходом:
(gdb)
bash: exec: non-existing-file: не найден
163 exit_value = EX_NOTFOUND; /* As per Posix.2, 3.14.6 */
(gdb)
165 goto failed_exec;
(gdb)
235 FREE (command);
(gdb)
237 if (subshell_environment || (interactive == 0 && no_exit_on_failed_exec == 0))
(gdb)
238 exit_shell (exit_value);
(gdb)
[Inferior 1 (process 4034) exited with code 0177]
Печать переменных:
(gdb) p subshell_environment
$1 = 0
(gdb) p interactive
$2 = 0
(gdb) p no_exit_on_failed_exec
$3 = 0
Оказывается, оболочка неинтерактивна (interactive=0
) при использовании встроенного exec
. Это причина такого поведения.
Это противоречит задокументированному поведению, так что, можно сказать, вы нашли ошибку.
Здесь происходит изменение non-interactive
interactive=0
(evalfile.c
):
interactive:
Old value = 1
New value = 0
_evalfile (filename=0xa014c8 "exec1.sh", flags=14)
at evalfile.c:226
223 if (flags & FEVAL_NONINT)
224 interactive = 0;
из-за flags=14
flags
устанавливаются на более высокий уровень в функции source_file
(evalfile.c
):
#1 0x0000000000485dcf in source_file (filename=0x9fb8c8 "exec1.sh", sflags=0)
338 flags = FEVAL_BUILTIN|FEVAL_UNWINDPROT|FEVAL_NONINT;
339 if (sflags)
340 flags |= FEVAL_NOPUSHARGS;
341 /* POSIX shells exit if non-interactive and file error. */
342 if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
343 flags |= FEVAL_LONGJMP;
344 rval = _evalfile (filename, flags);
И определяет это:
#define FEVAL_BUILTIN 0x002
#define FEVAL_UNWINDPROT 0x004
#define FEVAL_NONINT 0x008
-> флаги 1110 = 14.
Итак, как я понимаю, это ошибка: source
выполняет команды в текущей оболочке, но устанавливает флаг FEVAL_NONINT 0x008
- неинтерактивный (ошибка здесь): evalfile.c
, в source_file
:
338 flags = FEVAL_BUILTIN|FEVAL_UNWINDPROT|FEVAL_NONINT;
Я создал проблему на трекере ошибок:
http://savannah.gnu.org/support/index.php?108980
Посмотрел бы это.
РЕДАКТИРОВАТЬ1:Как сторонник Bash прокомментировал билет
«В настоящее время оболочка не является интерактивной при чтении аргумента файла во встроенную программу-источник (interactive == 0), хотя сама оболочка является интерактивной (interactive_shell == 1)».
Также, по его словам, такое поведение, скорее всего, не изменится в ближайшее время.
Вопрос сейчас кажется закрытым.