“ exec”命令有什么作用?


108

我不明白bash命令exec。我已经看到它在脚本内部使用过,以将所有输出重定向到文件(如本示例所示)。但是我不明白它是如何工作的或者它通常是做什么的。我已经阅读了手册页,但我听不懂。


您是否熟悉一个流程
fkraiem

1
@fkraiem是什么意思?
becko 2014年

对不起,我的意思是“什么”。:p但答案似乎是否定的。
fkraiem

但是实际上您的脚本exec以一种特殊的方式使用,这种方式可以更简单地解释,我将写一个答案。
fkraiem

Answers:


88

man bash 说:

exec [-cl] [-a name] [command [arguments]]
      If command is specified, it replaces the shell.  No new  process
      is  created.  The arguments become the arguments to command.  If
      the -l option is supplied,  the  shell  places  a  dash  at  the
      beginning  of  the  zeroth  argument passed to command.  This is
      what login(1) does.  The -c option causes command to be executed
      with  an empty environment.  If -a is supplied, the shell passes
      name as the zeroth argument to the executed command.  If command
      cannot  be  executed  for  some  reason, a non-interactive shell
      exits, unless the execfail shell option  is  enabled.   In  that
      case,  it returns failure.  An interactive shell returns failure
      if the file cannot be executed.  If command  is  not  specified,
      any  redirections  take  effect  in  the  current shell, and the
      return status is 0.  If there is a redirection error, the return
      status is 1.

最后两行很重要:如果您自己运行exec而没有命令,它将仅使重定向应用于当前shell。您可能知道,当您运行时command > file,的输出将command被写入file而不是写入您的终端(这称为重定向)。如果exec > file改为运行,则重定向将应用于整个外壳程序:由外壳程序产生的任何输出都将写入file而不是写入终端。例如这里

bash-3.2$ bash
bash-3.2$ exec > file
bash-3.2$ date
bash-3.2$ exit
bash-3.2$ cat file
Thu 18 Sep 2014 23:56:25 CEST

我首先开始一个新的bash外壳。然后,在这个新的shell中运行exec > file,以便将所有输出重定向到file。确实,在那之后我运行了,date但是没有任何输出,因为输出被重定向到file。然后退出外壳程序(以便不再应用重定向),然后看到file确实包含date我先前运行的命令的输出。


42
这仅仅是部分解释。exec还可以用命令替换当前的shell进程,以便父级可以使用一种方式,而子级拥有pid。这不仅用于重定向。请添加此信息
Sergiy Kolodyazhnyy 2016年

3
在@SergiyKolodyazhnyy的评论之后,我刚才遇到的导致我进入此页面的示例是docker-entrypoint.sh,其中在对nginx配置执行各种操作之后,脚本的最后一行是exec nginx <various nginx arguments>。这意味着nginx接管了bash脚本的pid,现在nginx是容器的主要运行进程,而不是脚本。我认为这只是为了清洁,除非其他人知道更具体的原因?
路加·格里菲思

1
@Luke这称为“包装脚本”。也gnome-terminal有一个例子,至少在14.04上有一个包装器脚本来设置参数。实际上,这是他们的唯一目的-设定艺术和环境。另一种情况是清理-首先杀死进程的先前实例并启动新进程
Sergiy Kolodyazhnyy

exec类似于nginx@LukeGriffiths给出的示例的另一个示例是~/.vnc/xstartup脚本,该脚本vncserver用于配置VNC服务器进程,然后依次配置exec gnome-sessionor exec startkde等等。
Trevor Boyd Smith

@LukeGriffiths,exec在容器启动脚本中使用的主要原因是PID 1(容器的ENTRYPOINT)在Docker中具有特殊意义。这是一个接收信号的主要过程,当它存在时,容器也会退出。exec这只是sh从此命令链中删除并使守护程序成为容器的主要过程的一种方法。
公里

46

exec 是具有两种截然不同的行为的命令,具体取决于是否使用了至少一个参数,或者根本不使用任何参数。

  • 如果传递了至少一个参数,则将第一个作为命令名称,并exec尝试将其作为命令执行,将剩余的参数(如果有的话)传递给该命令并管理重定向(如果有的话)。

  • 如果作为第一个参数传递的命令不存在,则当前的shell(不仅是exec命令)将错误退出。

  • 如果该命令存在并且可执行,它将替换当前的shell。这意味着,如果exec出现在脚本中,则将永远不会执行 exec调用之后的指令(除非exec它本身在子shell中)。exec永远不会回来。诸如“ EXIT”之类的外壳陷阱也不会被触发。

  • 如果未传递任何参数,exec则仅用于重新定义当前的shell文件描述符。exec与前面的情况不同,shell在之后继续执行,但是标准的输入,输出,错误或任何已重定向的文件描述符都将生效。

  • 如果某些重定向使用/dev/null,则来自该重定向的任何输入都将返回EOF,并且丢弃给它的所有输出。

  • 您可以通过将其-用作源或目标来关闭文件描述符,例如exec <&-。随后的读取或写入将失败。

这是两个示例:

echo foo > /tmp/bar
exec < /tmp/bar # exec has no arguments, will only affect current shell descriptors, here stdin
cat # simple command that read stdin and write it to stdout

该脚本将输出“ foo”作为cat命令,而不是像通常情况下那样等待用户输入,而是从包含foo的/ tmp / bar文件中获取其输入。

echo foo > /tmp/bar
exec wc -c < /tmp/bar # exec has two arguments, the control flow will switch to the wc command
cat

该脚本将显示4(/ tmp / bar中的字节数)并立即结束。该cat命令将不会执行。


4
`有些旧帖子从未真正变老... +1。
Cbhihe

3
如果某些重定向使用/ dev / null,则将关闭关联的文件描述符。 不,它确实确实重定向到或从重定向/dev/null,因此写入仍然成功,并且读取返回EOF。 close(2)在fd上执行操作会导致读/写系统调用返回错误,exec 2>&-例如,您可以执行此操作。
彼得·科德斯

2
自己尝试exec 3</dev/null; ls -l /proc/self/fd::注意,fd 3将在/ dev / null上以只读方式打开。然后使用再次关闭它exec 3<&-,您可以ls -l /proc/$$/fd再次看到Shell进程不再具有fd 3了。(exec <&-在脚本中关闭stdin 可能很有用,但交互式地是注销。)
Peter Cordes

@PeterCordes你是完全正确的。答案已更新。谢谢!
jlliagre

1
这个答案很棒,因为它解释了当前最受欢迎的答案的两个用例exec仅讨论一个用例,而g_p给出的另一个答案仅涉及另一个用例。对于这样一个复杂的主题,这个答案很好,简洁/可读。
Trevor Boyd Smith

33

要了解exec您需要首先了解fork。我正在努力保持简短。

  • 当您在路上岔路口时,通常会有两种选择。Linux程序在遇到fork()系统调用时会遇到 麻烦。

  • 普通程序是系统命令,以系统形式存在于系统中。当执行这样的程序时,将创建一个新的过程。该子进程与其父进程具有相同的环境,只是进程ID号不同。此过程称为 分叉

  • 分叉为现有流程提供了一种开始新流程的方法。但是,在某些情况下,子进程与父进程不在同一个程序中。在这种情况下exec使用。exec 将用程序二进制文件中的信息替换当前正在运行的进程的内容。
  • 在分支过程之后,子过程的地址空间将被新的过程数据覆盖。这是通过对系统的exec调用完成的。

3
您能否解释为什么exec可以重定向脚本输出,如我发布的链接中所示?
becko 2014年

1
我发现这不清楚:“但是,子进程可能与父进程不在同一个程序中”
cdosborn 18-10-15

6

在中bash,如果您这样做help exec

$ help exec
exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
    Replace the shell with the given command.

    Execute COMMAND, replacing this shell with the specified program.
    ARGUMENTS become the arguments to COMMAND.  If COMMAND is not specified,
    any redirections take effect in the current shell.

    Options:
      -a name   pass NAME as the zeroth argument to COMMAND
      -c        execute COMMAND with an empty environment
      -l        place a dash in the zeroth argument to COMMAND

    If the command cannot be executed, a non-interactive shell exits, unless
    the shell option `execfail' is set.

    Exit Status:
    Returns success unless COMMAND is not found or a redirection error occurs.

相关位:

If COMMAND is not specified, any redirections take effect in the current shell.

exec是一个shell内建,这是壳等效的exec家庭的系统调用G_P讲的(和它的手册页,你似乎已经读)。如果未指定任何命令,它仅具有POSIX要求的功能,该功能会影响当前的shell。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.