6

В документации к exec говорится, что она выйдет из оболочки в случае ошибки, если текущая оболочка не является интерактивной и опция execfail не установлена.

Я заметил странное поведение в интерактивной оболочке bash, которое я не могу объяснить с помощью документации. Эта команда

exec non-existent-file

выдает сообщение об ошибке, и оболочка остается активной, как и ожидалось. Но если я помещу ту же команду в файл и source файл, текущая оболочка будет закрыта из-за сбоя exec.

Может ли кто-нибудь помочь мне понять, почему это происходит?

1 ответ1

2

Как я чувствую, это ошибка. Ниже какая-то "детективная история".

Да, в коде 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)».

Также, по его словам, такое поведение, скорее всего, не изменится в ближайшее время.

Вопрос сейчас кажется закрытым.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .