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

评论

您是否了解流程是什么?

@fkraiem是什么意思?

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

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

相关:unix.stackexchange.com/q/296838/85039

#1 楼

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,则重定向将应用于整个shell:shell产生的任何输出都将写入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外壳。然后,在这个新的外壳程序中,我运行exec > file,以便将所有输出重定向到file。确实,此后,我运行date,但没有任何输出,因为输出被重定向到file。然后退出外壳程序(以便不再应用重定向),然后看到file确实包含我先前运行的date命令的输出。

评论


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

– Sergiy Kolodyazhnyy
16年8月31日在13:23

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

–卢克·格里菲思(Luke Griffiths)
18年11月21日在19:56

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

– Sergiy Kolodyazhnyy
18年11月21日在20:18

类似于@LukeGriffiths提供的nginx示例的另一个exec示例是〜/ .vnc / xstartup脚本,vncserver使用该脚本配置VNC服务器进程,然后配置gnome-session或exec startkde等。

–特雷弗·博伊德·史密斯
19年1月22日在13:57

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

–kkm
19年2月13日在22:39

#2 楼

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


如果至少传递了一个参数,第一个作为命令名称,并且exec尝试将其作为将其余参数(如果有)传递给该命令并管理重定向(如果有)的命令来执行。
如果作为第一个参数传递的命令没有执行,如果存在,则当前外壳程序(不仅是exec命令)都会错误退出。
如果命令存在并且可执行,它将替换当前外壳程序。这意味着,如果脚本中出现exec,则将永远不会执行exec调用之后的指令(除非exec本身在子外壳中)。 exec永不返回。诸如“ EXIT”之类的外壳陷阱也不会被触发。
如果未传递任何参数,则exec仅用于重新定义当前的外壳文件描述符。与以前的情况不同,shell在exec之后继续执行,但是标准的输入,输出,错误或任何已重定向的文件描述符都将生效。
如果某些重定向使用/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命令将不会执行。

评论


`一些旧帖子从未真正变老... +1。

– Cbhihe
17 Mar 23 '17 at 11:33

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

– Peter Cordes
17年7月7日在2:59



自己尝试:exec 3
– Peter Cordes
17年7月7日在3:01



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

– jlliagre
17年7月7日在5:43

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

–特雷弗·博伊德·史密斯
19年1月22日在14:09



#3 楼

要了解exec,您需要先了解fork。我正在尝试使其简短。


在路上遇到叉子时,通常有两种选择。 Linux程序遇到一个
fork()系统调用时,便会遇到麻烦。
普通程序是系统命令,它们以编译形式存在于您的系统上。当执行这样的程序时,会创建一个新进程。该子进程与其父进程具有相同的环境,
只有进程ID号不同。此过程称为
forking。
Forking提供了一种用于现有进程启动新进程的方法。但是,在某些情况下,子进程可能与父进程不在同一个程序中。在这种情况下,使用execexec
将用程序二进制文件中的
信息替换当前正在运行的进程的内容。
分叉过程之后,子进程的地址空间被
覆盖。新过程数据。这是通过对系统的exec
调用来完成的。


评论


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

–壁虎
2014年9月18日在21:45

我发现这种不清楚的情况“但是,在某些情况下,子进程与父进程不在同一个程序中”

–cdosborn
18-10-15在22:34

#4 楼

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是一个外壳内置,这等效于G_P谈到的exec系列系统调用的外壳程序(以及您看过的联机帮助页)。如果未指定任何命令,它仅具有POSIX强制性功能即可影响当前shell。