exec命令在shell脚本中有哪些用途?

有人能用简单的例子解释一下exec命令在shell脚本中的用途吗?

342191 次浏览

exec内置命令镜像内核中的函数,它们有一系列基于execve的函数,通常从C调用。

exec替换当前进程中的当前程序,而不__abc1生成一个新进程。这不是您在编写的每个脚本中都会用到的东西,但有时会很方便。以下是我使用它的一些场景;

  1. 我们希望用户在不访问shell的情况下运行特定的应用程序。我们可以更改/etc/passwd中的登录程序,但也许我们希望从启动文件中使用环境设置。因此,在(say) .profile中,最后一条语句是这样说的:

     exec appln-program
    

    所以现在没有壳层可以回去了。即使appln-program崩溃,最终用户也无法获得shell,因为它不存在——exec替换了它

  2. 我们想要使用一个不同于/etc/passwd.中的shell有些网站不允许用户修改登录shell,这看起来很愚蠢。我知道的一个网站让每个人都从csh开始,每个人都在他们的.login (csh启动文件)中放入一个对ksh的调用。虽然这是有效的,但它留下了一个流浪的csh进程正在运行,注销是两个阶段,这可能会令人困惑。因此,我们将其改为exec ksh,它只是用korn shell取代了c-shell程序,并使一切变得更简单(这还存在其他问题,例如ksh不是一个登录shell)。

  3. 只是为了保存进程。如果我们调用prog1 -> prog2 -> prog3 -> prog4等,并且永不返回,那么每个调用都是一个exec。它节省了资源(不可否认,除非重复),并使关机更简单。

你显然在某个地方看到过exec的使用,也许如果你展示了困扰你的代码,我们可以证明它的使用是正确的。

我意识到我上面的答案是不完整的。在shell中有exec两个用法,比如kshbash——用于打开文件描述符。下面是一些例子:

exec 3< thisfile          # open "thisfile" for reading on file descriptor 3
exec 4> thatfile          # open "thatfile" for writing on file descriptor 4
exec 8<> tother           # open "tother" for reading and writing on fd 8
exec 6>> other            # open "other" for appending on file descriptor 6
exec 5<&0                 # copy read file descriptor 0 onto file descriptor 5
exec 7>&4                 # copy write file descriptor 4 onto 7
exec 3<&-                 # close the read file descriptor 3
exec 6>&-                 # close the write file descriptor 6

注意这里的间距非常重要。如果在fd数和重定向符号之间放置空格,则exec将恢复到原始含义:

  exec 3 < thisfile       # oops, overwrite the current program with command "3"

有几种方法可以使用它们,在ksh上使用read -uprint -u,在bash上,例如:

read <&3
echo stuff >&4

只是为了用一个简短的新手友好的简短答案来扩大接受的答案,你可能不需要exec

如果你还在这里,下面的讨论有望揭示原因。当你跑步的时候,说,

sh -c 'command'

你运行一个sh实例,然后启动command作为该sh实例的子实例。当command结束时,sh实例也结束。

sh -c 'exec command'

运行一个sh实例,然后用command二进制文件替换sh实例,并运行该实例。

当然,这两种方法在这个有限的上下文中都是无用的;你只是想要

command

有一些边缘情况,你希望shell读取它的配置文件或以其他方式设置环境作为运行command的准备。这几乎是exec command有用的唯一情况。

#!/bin/sh
ENVIRONMENT=$(some complex task)
exec command

这做了一些准备环境的工作,以便它包含所需的内容。一旦完成了这一步,sh实例就不再需要了,因此简单地用command进程替换sh实例,而不是让sh作为子进程运行并等待它,然后在它完成时立即退出,这是一个(小)优化。

类似地,如果你想在shell脚本的末尾释放尽可能多的资源用于重载命令,你可能想要exec该命令作为优化。

如果有什么东西强迫你运行sh,但你真的想运行其他东西,exec something else当然是一个替代不需要的sh实例的变通方法(例如,如果你真的想运行你自己的漂亮的gosh而不是sh,但你的/etc/shells中没有列出,所以你不能指定它作为你的登录shell)。

exec操作文件描述符的第二个用途是一个单独的主题。公认的答案很好地涵盖了这一点;为了保持它的自成体系,对于任何exec后面跟着重定向而不是命令名的东西,我都将遵循手册。