Shell脚本退出时无法终止nc进程的问题排查
问题分析
你的脚本出现nc进程残留的原因主要有三点:
- PID跟踪错误:
honeypot_pid+=($!)获取的是后台运行的while循环进程PID,而非nc进程的PID,导致ctrl_c函数无法精准杀死nc。 - 子进程脱离父进程:
nc运行在子shell中,当脚本主进程退出后,nc会成为孤儿进程被系统初始化进程接管,不会随脚本终止而退出。 nc监听状态特性:处于监听状态的nc不会主动响应父进程的终止信号,只有当客户端断开连接时才会自行退出。
修复方案
以下两种方案都能解决问题,按需选择:
方案一:精准跟踪nc进程PID
修改server函数,直接记录nc的PID,确保终止时能精准查杀:
# Netcat server server () { while true; do # 单独输出日志头,避免子shell层级 echo -e "--------" $(date) "--------\n" >> honeypot.log 2>&1 # 后台运行nc并记录PID nc -vnlp $port < banner.txt >> honeypot.log 2>&1 & local nc_pid=$! honeypot_pid+=($nc_pid) # 等待当前nc进程结束后,再启动下一次监听 wait $nc_pid done & }
同时简化ctrl_c函数,直接杀死记录的nc进程:
function ctrl_c() { echo -e "\nEncerrando o servidor..." # 杀死所有记录的nc进程,忽略已终止进程的错误输出 for pid in "${honeypot_pid[@]}"; do kill "$pid" 2>/dev/null done exit 1 }
方案二:通过进程组批量查杀
利用进程组特性,一次性杀死脚本及其所有子进程(包括nc),无需单独跟踪PID:
function ctrl_c() { echo -e "\nEncerrando o servidor..." # 杀死当前脚本所在进程组的所有进程,忽略错误输出 kill -- -$$ 2>/dev/null exit 1 }
同时可以简化server函数,去掉不必要的子shell:
# Netcat server server () { while true; do echo -e "--------" $(date) "--------\n" >> honeypot.log 2>&1 nc -vnlp $port < banner.txt >> honeypot.log 2>&1 done & }
-- -$$表示杀死进程ID为$$(当前脚本PID)的进程组内所有进程,所有由脚本启动的子进程都会被一并终止。
额外优化建议
- 移除
killall honeypot.sh:脚本退出时自身会终止,无需额外查杀,反而可能误杀其他同名脚本。 - 添加
2>/dev/null到kill命令后:避免因进程已终止而输出错误信息,提升脚本运行的整洁性。
内容的提问来源于stack exchange,提问作者Rayan Araujo
相关产品推荐
相关产品推荐

