首页 > 解决方案 > 为什么在 shell 脚本中调用 exec 时会生成已失效的进程?

问题描述

为什么在 shell 脚本中调用 exec 时会生成已失效的进程?

因为在启动 snmpd 之前应该设置和预加载一些额外的 configure 和 sharelib,

所以我像下面这样使用shell脚本,但问题是每次启动shell脚本时都会生成一个僵尸进程。

据我所知,exec会替换原来的shell进程26452,为什么会生成一个子进程26453变成僵尸?

$# ps -ef | grep snmpd
root     26452 12652  0 10:24 pts/4    00:00:00 snmpd udp:161,udp6:161 -f -Ln -I -system_mib ifTable -c /opt/snmp/config/snmpd.conf
root     26453 26452  0 10:24 pts/4    00:00:00 [snmpd_wapper.sh] <defunct>

如何避免僵尸进程,请帮助!

cat /home/xpeng/snmpd_wapper.sh
#!/bin/bash

 ( sleep 2;/opt/snmp/bin/snmpusm -v 3 -u myuser -l authNoPriv -a MD5 -A xpeng localhost create top myuser >/dev/null 2>&1; \
 /opt/snmp/bin/snmpvacm -v 3 -u myuser -l authNoPriv -a MD5 -A xpeng localhost createSec2Group 3 top RWGroup >/dev/null 2>&1; \
 /opt/snmp/bin/snmpvacm -v 3 -u myuser -l authNoPriv -a MD5 -A xpeng localhost createView all .1 80 >/dev/null 2>&1; \
 /opt/snmp/bin/snmpvacm -v 3 -u myuser -l authNoPriv -a MD5 -A xpeng localhost createAccess RWGroup 3 1 1 all all none >/dev/null 2>&1 ) &

 LIBRT=/usr/lib64
 if [ "$(. /etc/os-release; echo $NAME)" = "Ubuntu" ]; then
    LIBRT=/usr/lib/x86_64-linux-gnu
 fi
 echo $$>/tmp/snmpd.pid
 export LD_PRELOAD=$LD_PRELOAD:$LIBRT/librt.so:/opt/xpeng/lib/libxpengsnmp.so
 exec -a "snmpd" /opt/snmp/sbin/snmpd udp:161,udp6:161 -f -Ln -I -system_mib,ifTable -c /opt/snmp/config/snmpd.conf

标签: linuxshellexeczombie-processdefunct

解决方案


这是父进程wait对任何子进程的责任。子进程从它死亡到父进程为它服务时将是一个僵尸wait

您启动了一个子进程,但随后您用于exec替换父进程。新程序不知道它有孩子,所以它没有wait。因此,子进程成为僵尸,直到父进程死亡。

这是一个 MCVE:

#!/bin/sh
sleep 1 &      # This process will become a zombie
exec sleep 30  # Because this executable won't `wait`

您可以改为使用双叉

#!/bin/sh
(             # Start a child shell
  sleep 1 &   # Start a grandchild process
)             # Child shell dies, grandchild is given to `init`
exec sleep 30 # This process now has no direct children

推荐阅读