为什么“exec non-existent-file”在源脚本中退出shell?

Ale*_*rov 6 bash

的文档exec说,如果当前 shell 是非交互式的并且execfail没有设置选项,它会在出错的情况下退出 shell 。

我注意到交互式 bash shell 中有一个奇怪的行为,但我无法用文档解释。这个命令

exec non-existent-file
Run Code Online (Sandbox Code Playgroud)

产生一条错误消息,并且 shell 保持活动状态,正如预期的那样。但是如果我将相同的命令放入一个文件和source那个文件中,当前的 shell 将被失败的 exec 退出。

有人可以帮助我理解为什么会发生这种情况吗?

Joh*_*est 2

据我感觉,这是一个错误。下面是某种“侦探故事”。

\n\n

是的,在exec.def代码中我们看到:

\n\n
if (subshell_environment || (interactive == 0 && no_exit_on_failed_exec == 0))\n  exit_shell (exit_value);\n
Run Code Online (Sandbox Code Playgroud)\n\n

因此,当在子 shell 中运行时exec,会导致在非交互式 shell 上使用false“no_exit_on_failed_exec”退出 shell\nb)exec

\n\n

对于交互式 shell,如果该命令存在,则该 shell 将替换为\n调用的命令:

\n\n
\n

执行

\n\n

此 shell 内置命令用指定的\n 命令替换当前进程。通常,当 shell 遇到命令时,它会派生出一个\n 子进程来实际执行该命令。\n 使用 exec 内置命令,\n shell 不会派生,并且命令 exec\'ed 会替换 shell。\因此,当在脚本中使用时,当执行的命令终止时,它会强制退出脚本

\n\n

示例 15-24。执行的效果

\n\n
#!/bin/bash\nexec echo "Exiting \\"$0\\" at line $LINENO."   # Exit from script here.\n# $LINENO is an internal Bash variable set to the line number it\'s on.\n**# The following lines never execute.**\n
Run Code Online (Sandbox Code Playgroud)\n\n

http://www.tldp.org/LDP/abs/html/internal.html#EXECREF

\n
\n\n

sourcecommand 不会调用 subshel​​l - 它强制所有命令在当前的活动 shell 中执行(例如,它用于设置变量 - 不是用于将退出的某些子 shell,而是用于当前的 shell)。source因此,在 shell 中直接执行命令后,您的 shell 将终止(这是预期的行为)。

\n\n
\n

当使用“source”运行脚本时,它会在现有 shell 中运行,\n 脚本创建或修改的任何变量将在脚本完成后保持可用。\n http://ss64.com/bash/source .html

\n
\n\n

我已经编译bash-4.2并在gdb调试器中运行它。

\n\n

这些是退出前执行的最后命令:

\n\n
(gdb) \nbash: exec: non-existing-file: \xd0\xbd\xd0\xb5 \xd0\xbd\xd0\xb0\xd0\xb9\xd0\xb4\xd0\xb5\xd0\xbd\n163       exit_value = EX_NOTFOUND; /* As per Posix.2, 3.14.6 */\n(gdb) \n165       goto failed_exec;\n(gdb) \n235   FREE (command);\n(gdb) \n237   if (subshell_environment || (interactive == 0 && no_exit_on_failed_exec == 0))\n(gdb)\n238     exit_shell (exit_value);\n(gdb)\n[Inferior 1 (process 4034) exited with code 0177]\n
Run Code Online (Sandbox Code Playgroud)\n\n

打印变量:

\n\n
(gdb) p subshell_environment \n$1 = 0\n(gdb) p interactive\n$2 = 0\n(gdb) p no_exit_on_failed_exec \n$3 = 0\n
Run Code Online (Sandbox Code Playgroud)\n\n

事实证明,interactive=0在获取内置exec. 这就是这种行为的原因。\n它与记录的行为相矛盾,因此,有人可能会说,您发现了一个错误。

\n\n

non-interactive, ,的更改interactive=0发生在 ( evalfile.c) 处:

\n\n
interactive:\nOld value = 1\nNew value = 0\n_evalfile (filename=0xa014c8 "exec1.sh", flags=14)\nat evalfile.c:226\n223  if (flags & FEVAL_NONINT)\n224    interactive = 0;\n
Run Code Online (Sandbox Code Playgroud)\n\n

由于flags=14.\nflags被设置为更高的级别,在函数source_file( evalfile.c) 中:

\n\n
#1  0x0000000000485dcf in source_file (filename=0x9fb8c8 "exec1.sh", sflags=0)\n\n338  flags = FEVAL_BUILTIN|FEVAL_UNWINDPROT|FEVAL_NONINT;\n339  if (sflags)\n340    flags |= FEVAL_NOPUSHARGS;\n341  /* POSIX shells exit if non-interactive and file error. */\n342  if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)\n343    flags |= FEVAL_LONGJMP;\n344  rval = _evalfile (filename, flags);\n
Run Code Online (Sandbox Code Playgroud)\n\n

定义是:

\n\n
#define FEVAL_BUILTIN       0x002\n#define FEVAL_UNWINDPROT    0x004\n#define FEVAL_NONINT        0x008\n
Run Code Online (Sandbox Code Playgroud)\n\n

-> 标志 1110 =14。

\n\n

因此,据我了解,这是一个错误:source在当前 shell 中执行命令,但设置标志FEVAL_NONINT 0x008- 非交互式\n(此处为错误):\n evalfile.c,位于source_file

\n\n
338 flags = FEVAL_BUILTIN|FEVAL_UNWINDPROT|FEVAL_NONINT;\n
Run Code Online (Sandbox Code Playgroud)\n\n

我在错误跟踪器上创建了一个问题:

\n\n

http://savannah.gnu.org/support/index.php?108980

\n\n

会看的。

\n\n
\n\n

EDIT1:\n作为 bash 支持者对票证的评论

\n\n
\n

“当读取文件参数到内置源时,shell 当前不是交互式的(interactive == 0),尽管 shell 本身是交互式的(interactive_shell == 1)。”

\n
\n\n

而且,正如他所说,这种行为在不久的将来可能不会改变。

\n\n

这个问题现在似乎已经结束了。

\n