Bash内置exec的用例/实际示例


Answers:


18

exec通常在Shell脚本中使用,主要用作启动其他二进制文件的包装。例如:

#!/bin/sh

if stuff;
    EXTRA_OPTIONS="-x -y -z"
else
    EXTRA_OPTIONS="-a foo"
fi

exec /usr/local/bin/the.real.binary $EXTRA_OPTIONS "$@"

这样,在包装程序完成运行之后,“实际”二进制文件将接管,不再有临时占据进程表中同一插槽的包装程序脚本的任何痕迹。“真正的”二进制文件是启动它的任何对象的直接子代,而不是孙子代。

您在问题中还提到了I / O重定向。那是完全不同的用例,exec与用另一个进程替换外壳无关。当exec没有参数时,如下所示:

exec 3>>/tmp/logfile

那么命令行上的I / O重定向将在当前Shell进程中生效,但是当前Shell进程将继续运行并继续执行脚本中的下一个命令。


1
您可能会说这两种情况是相关的,因为两者都exec告诉外壳程序不要在子进程中执行操作(执行命令或执行重定向),而要在同一进程中执行。
斯特凡Chazelas

5

我使用了exec内置的Shell 来获取Java程序的进程ID(PID)。现在可能有一种从Java内部获取PID的方法,但是几年前还没有。进程拥有自己的PID后,可以将其写到PID文件中(查找/var/run/后缀为'.pid'的文件名),以允许管理程序知道正在运行的进程的PID,并防止出现第二个实例同一台服务器运行。它的工作原理如下:

exec java -cp=YourServer.jar StartClass -p $$

main()类方法中的代码StartClass处理参数解析,并可以找到其自己的进程ID。


2

为了娱乐,请在具有用户进程计费和限制的系统上在后台运行以下程序(转换为您选择的实现语言)。

while(true) fork();

现在,您被允许使用的进程表中的每个插槽都充满了该正在运行的程序的副本,您打算如何杀死它?启动kill(1)需要另一个进程插槽,而您没有。让shell用kill命令替换自己肯定很方便...

exec /bin/kill -9 -1

(假设您的系统在/ bin / kill处具有kill(1)。“ exec`which kill -9 -1”可能更安全。)这会将SIGKILL发送给您可以使用的每个进程。

(注意:除非进程限制始终允许其外壳程序有新的登录名,否则请不要从启动外壳程序注销。如果这样做,清理起来会更加困难。我当然没有在启动过程中这样做。 90年代初期。不。)


3
(1)如果您实际显示了exec在这种情况下有用的命令,则此答案会稍好一点。(2)这个答案有些陈旧;该kill命令多年来一直是bash中的内置命令,主要是由于这种担忧。
G-Man说'Resstate Monica''Mar

@ G-Man:您了解您的项目(2)使此答案对OP做出了准确的反应吗?
埃里克·塔

不,我不明白。请给我解释一下。
G-Man说'恢复莫妮卡

4
我没有关注你。这个问题并没有要求所有 bash内置命令的实际示例。它要求提供-的示例,execkill内置的事实与内置的确没有任何关系exec
G-Man说'Resstate Monica''Mar

1
我刚刚阅读了您对答案的更新。(1)猜猜是什么?如果进程表已满,则命令替换(例如`which kill`)也不起作用。(2)顺便说一句,$(…)建议使用该`…`表格。(3)但是在目录上猜测没有任何危险。如果您不小心输入exec /binn/kill,您只会收到一条错误消息,而您的shell也不会消失。(4)但是,你甚至都不需要什么目录的担心kill是,  exec用途$PATH,就像正常的命令,所以exec kill …作品(假设你/bin在你的搜索路径)。
G-Man说'恢复莫妮卡'

1
  • 这类似于Bruce需要知道进程的PID的示例:

    (cmdpid = $ BASHPID;(sleep 300; kill“ $ cmdpid”)&exec long-running-command

    在你里面

    1. 启动一个子shell(外部()),
    2. 找出子外壳的PID。($$会给你的主壳的PID)。
    3. 分离一个子子shell,该子子shell在超时后会终止您的进程,并且
    4. 在您在步骤1中创建的子外壳程序的过程中运行命令。

    这将运行long-running-command,但仅在预定的有限时间内进行。 

  • 这有点轻浮,但是,如果您决定要在其余的登录会话中成为root用户(或其他用户),则可以这样做exec su

    实际上,我可以想象一个场景,在这种情况下真的很有用。假设您已登录到远程系统,并且由于某种原因,断开连接并开始新的连接存在问题。例如,假设远程系统具有遵循计划的防火墙。完成连接后,您将被允许连接,并且建立的连接不会关闭,但是目前,新连接不被接受。

    您已经完成了想要做的事情,并且已经准备好注销。您的朋友Bob和您一起在房间里,他想在远程系统上做一些工作-但他无法连接。因此,您键入exec su - bob,然后在出现密码提示时,将工作站移交给他。现在,您的UID不需要任何处理(除非您在后台运行了某些东西),因此Bob将无法处理您的文件。他将有效地接管您的联系(在您的同意和合作下)。

    笔记:

    • 如果你不允许跑步,这当然是行不通的su
    • 它将被记录下来,因此您可能需要向他人解释您的动机。由于您正在规避策略(防火墙计划),因此可能会遇到麻烦。
    • 我不保证它是100%安全的。例如,who可能仍会显示您的名字。可以想象有些(写得不好)程序会使用它来认为Bob是您,并允许他访问您的资源。
    • 如果系统进行审核,则Bob的操作可能会以您的名字审核。

请注意,实际上在大多数shell中,(a;b)它已经与(a;exec b)shell 相同,可以为子shell中的最后一个命令优化派生。唯一的例外似乎是bashmksh。使用exec有助于保证这一点。
斯特凡Chazelas
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.