25

我想使用 bashEXIT陷阱使用它exec来避免产生新进程。这可能吗?

那是,

#!/bin/bash
touch $0.$$
trap "rm -v $0.$$" EXIT
/bin/echo Hello

$0.$$使用 bash 的EXIT陷阱删除临时文件while

#!/bin/bash
touch $0.$$
trap "rm -v $0.$$" EXIT
exec /bin/echo Hello

从不“触发”陷阱(完成后没有来自rm, 文件的消息$0.$$)。

当然,陷阱不能触发是有道理的,因为 bash 在exec. 有没有办法让它工作使用exec?诚然,这是出于好奇而不是实际问题。

4

1 回答 1

34

一般来说,没有。由于您提到的原因,这是不可能的。

虽然这是一个无聊的答案。让我们看看我们的解决方法选项:

如果我们更关心 exec 语义而不是启动多个进程,我们可以对任意可执行文件执行以下操作:

{ while kill -0 $$; do sleep 5; done; rm "$0.$$"; } &
exec ./file

这将exec文件并有另一个进程轮询它并在完成后进行清理。

如果我们想避免分叉并且我们正在执行的是另一个 shell 脚本,我们可以这样做

exec bash --rcfile <(echo 'trap "..." exit') -i ./file

exec文件并在之后进行清理(只要脚本没有exec或覆盖陷阱),而不启动新进程。sourceing 而不是execing 将产生相同的效果:

trap "..." exit
source ./file

如果我们想变得非常hacky,我们可以使用LD_PRELOAD覆盖exit(3)并运行我们选择的命令:

#include <stdlib.h>

void exit(int c) {
    char* cmd = getenv("EXIT");
    char *argv[] = { "bash", "-c", cmd, NULL };
    char *envp[] = { NULL };
    execvpe("bash", argv, envp);
}

我们可以将其编译为库:

$ gcc -shared -fPIC foo.c -o libfoo.so

然后将其预加载到任意动态链接的可执行文件中:

$ LD_PRELOAD=./libfoo.so EXIT='echo "This is a hack"' ls *foo*
foo.c  libfoo.so
This is a hack

这些技巧很有趣,但在现实世界中很少需要。更简单、更好和更规范的解决方案就是不exec

于 2014-06-09T02:12:11.023 回答