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


当前回答

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

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

sh -c 'command'

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

sh -c 'exec command'

运行一个sh实例,然后将该sh实例替换为命令二进制,并运行该sh实例。

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

command

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

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

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

类似地,如果希望为shell脚本末尾的重量级命令释放尽可能多的资源,则可能希望执行该命令作为优化。

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

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

其他回答

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

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

We want the user to run a specific application program without access to the shell. We could change the sign-in program in /etc/passwd, but maybe we want environment setting to be used from start-up files. So, in (say) .profile, the last statement says something like: exec appln-program so now there is no shell to go back to. Even if appln-program crashes, the end-user cannot get to a shell, because it is not there - the exec replaced it. We want to use a different shell to the one in /etc/passwd. Stupid as it may seem, some sites do not allow users to alter their sign-in shell. One site I know had everyone start with csh, and everyone just put into their .login (csh start-up file) a call to ksh. While that worked, it left a stray csh process running, and the logout was two stage which could get confusing. So we changed it to exec ksh which just replaced the c-shell program with the korn shell, and made everything simpler (there are other issues with this, such as the fact that the ksh is not a login-shell). Just to save processes. If we call prog1 -> prog2 -> prog3 -> prog4 etc. and never go back, then make each call an exec. It saves resources (not much, admittedly, unless repeated) and makes shutdown simplier.

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

编辑:我意识到我上面的答案不完整。exec在shell(如ksh和bash)中有两种用途,用于打开文件描述符。下面是一些例子:

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 -u或print -u,在bash上,例如:

read <&3
echo stuff >&4

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

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

sh -c 'command'

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

sh -c 'exec command'

运行一个sh实例,然后将该sh实例替换为命令二进制,并运行该sh实例。

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

command

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

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

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

类似地,如果希望为shell脚本末尾的重量级命令释放尽可能多的资源,则可能希望执行该命令作为优化。

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

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