执行另一个二进制文件时如何实现bash EXIT陷阱?

Rhy*_*ich 20 bash exec bash-trap

我想使用bash EXIT陷阱使用exec以避免产生新进程.这可能吗?

那是,

#!/bin/bash
touch $0.$$
trap "rm -v $0.$$" EXIT
/bin/echo Hello
Run Code Online (Sandbox Code Playgroud)

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

#!/bin/bash
touch $0.$$
trap "rm -v $0.$$" EXIT
exec /bin/echo Hello
Run Code Online (Sandbox Code Playgroud)

永远不会"触发"陷阱(完成后没有来自rm文件的消息$0.$$).

当然,它是有道理的,陷阱不会发射,因为bash不再受到控制exec.有没有办法让它工作使用exec?诚然,这不仅仅是出于好奇而不是实际问题.

tha*_*guy 22

一般来说,没有.你提到的原因是不可能的.

这是一个无聊的答案.我们来看看解决方法的选项:

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

{ while kill -0 $$; do sleep 5; done; rm "$0.$$"; } &
exec ./file
Run Code Online (Sandbox Code Playgroud)

exec文件将由另一个进程轮询并在完成后进行清理.

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

exec bash --rcfile <(echo 'trap "..." exit') -i ./file
Run Code Online (Sandbox Code Playgroud)

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

trap "..." exit
source ./file
Run Code Online (Sandbox Code Playgroud)

如果我们想要变得非常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);
}
Run Code Online (Sandbox Code Playgroud)

我们可以将其编译为库:

$ gcc -shared -fPIC foo.c -o libfoo.so
Run Code Online (Sandbox Code Playgroud)

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

$ LD_PRELOAD=./libfoo.so EXIT='echo "This is a hack"' ls *foo*
foo.c  libfoo.so
This is a hack
Run Code Online (Sandbox Code Playgroud)

这些黑客很有趣,但在现实世界中很少需要.更简单,更好,更规范的解决方案就是不exec.

  • 每当我想“是的,我已经看到了通过现代 shell 功能的组合可以完成的最奇怪的事情”,而每次我都错了。+1 (2认同)