MST
星途 面试题库

面试题:Bash复杂场景下的trap命令与脚本健壮性设计

假设你正在编写一个长期运行的Bash脚本,它会创建多个子进程并与之交互。要求在脚本接收到SIGTERM信号时,首先安全地关闭所有子进程,清理相关临时文件,并且在关闭过程中如果遇到子进程无法正常关闭的情况(例如,子进程陷入死锁或挂起),要有相应的处理机制(如尝试发送SIGKILL信号强制关闭),最后输出详细的关闭日志。请阐述实现这一复杂功能的完整设计思路和关键代码片段。
30.8万 热度难度
编程语言Bash

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 捕获SIGTERM信号:使用trap命令捕获SIGTERM信号,当接收到该信号时,执行清理函数。
  2. 管理子进程:在创建子进程时,记录它们的进程ID(PID),以便后续关闭。可以将PID存储在数组中。
  3. 安全关闭子进程:向每个子进程发送SIGTERM信号,尝试正常关闭它们。
  4. 处理异常关闭:如果子进程在一定时间内没有响应SIGTERM信号,发送SIGKILL信号强制关闭。
  5. 清理临时文件:在关闭子进程后,删除脚本创建的所有临时文件。
  6. 输出关闭日志:记录每个子进程的关闭状态以及清理临时文件的结果,输出详细的关闭日志。

关键代码片段

#!/bin/bash

# 存储子进程PID的数组
child_pids=()

# 捕获SIGTERM信号
trap 'cleanup' SIGTERM

# 函数:创建子进程
create_child_process() {
    some_command &
    child_pids+=($!)
}

# 函数:清理资源并关闭子进程
cleanup() {
    echo "Received SIGTERM, starting cleanup..."
    local log_file="shutdown_log.txt"
    exec > >(tee -a "$log_file") 2>&1

    # 向子进程发送SIGTERM信号
    for pid in "${child_pids[@]}"; do
        echo "Sending SIGTERM to child process $pid"
        kill -TERM "$pid"
    done

    # 等待子进程关闭,设置超时时间
    local timeout=10
    local remaining_pids=("${child_pids[@]}")
    while (( ${#remaining_pids[@]} > 0 )); do
        local pid="${remaining_pids[0]}"
        if wait "$pid" 2>/dev/null; then
            echo "Child process $pid has been successfully terminated"
        else
            if (( timeout <= 0 )); then
                echo "Timeout reached, sending SIGKILL to child process $pid"
                kill -KILL "$pid"
                if wait "$pid" 2>/dev/null; then
                    echo "Child process $pid has been forcefully terminated"
                else
                    echo "Failed to forcefully terminate child process $pid"
                fi
            else
                echo "Child process $pid did not respond to SIGTERM, waiting..."
                remaining_pids=("${remaining_pids[@]:1}")
                sleep 1
                ((timeout--))
            fi
        fi
    done

    # 清理临时文件
    if [ -e /tmp/temp_file ]; then
        echo "Deleting temporary file /tmp/temp_file"
        rm /tmp/temp_file
    else
        echo "Temporary file /tmp/temp_file does not exist"
    fi

    echo "Cleanup completed"
    exit 0
}

# 主脚本逻辑,示例:创建一些子进程
create_child_process
create_child_process

# 主循环,使脚本持续运行
while true; do
    sleep 1
done