【shell】为shell布置陷阱:trap捕捉信号

时间:2024-07-20 09:30:52

trapShell编程中的一种强大内置命令,‌用于捕获和处理信号。‌

信号是操作系统用于与正在运行的程序进行通信的机制。‌当发生某些特定事件时,‌操作系统会发送信号给程序,‌例如用户按下Ctrl+C终止程序的运行。‌trap命令允许我们在Shell脚本中捕获这些信号,‌并在发生时执行指定的操作。‌这种机制对于处理脚本中断、‌资源清理等场景非常有用。‌

trap命令的使用语法和常见应用场景如下:‌

清理资源:‌在脚本执行结束时,‌可以使用trap命令来执行清理操作,‌如关闭文件描述符、‌删除临时文件等。‌
记录错误日志:‌当脚本执行过程中发生错误时,‌trap命令可以用来将错误信息记录到日志文件中。‌
忽略特定信号:‌例如,‌可以忽略Ctrl+C信号,‌防止脚本被意外中断。‌
优雅地处理脚本终止:‌在脚本执行过程中模拟异常终止的情况,‌trap命令可以用来执行一些优雅的关闭操作,‌如清理资源、‌关闭数据库连接等。‌
trap命令的参数分为两部分:‌前一部分是接收到指定信号时将要采取的行动,‌后一部分是要处理的信号名。‌trap命令有三种形式分别对应三种不同的信号回应方式:‌

当脚本收到signal-list清单内列出的信号时,‌trap命令执行双引号中的命令。‌
trap不指定任何命令,‌接受信号的默认操作,‌默认操作是结束进程的运行。‌
trap指定一个空命令串,‌允许忽视信号,‌这在需要忽略某些信号时非常有用。‌
需要注意的是,‌脚本程序通常是以从上到下的顺序解释执行的,‌所以必须在你想保护的那部分代码以前指定trap命令。

主要用法及代码示例
以下是 trap 命令的十种主要用法及其代码示例:

用法 示例代码
捕获并处理指定信号 trap ‘echo “Signal received.”’ INT
忽略指定信号 trap ‘’ TERM
恢复默认的信号处理方式 trap - INT
设置 EXIT 信号处理函数 trap ‘cleanup’ EXIT
在函数内部设置 RETURN 信号处理函数 func() { trap ‘cleanup’ RETURN; … }
清除所有已设置的信号处理函数 trap - INT TERM EXIT
执行命令并在结束时恢复先前的信号处理方式 trap ‘cmd’ EXIT; cmd
在循环中使用 trap 避免在接收到信号时终止循环 while true; do trap ‘break’ INT; … ; done
使用函数作为信号处理函数 trap ‘cleanup’ INT; cleanup() { echo “Cleaning up…”; }
处理多个信号 trap ‘echo “Signal 1 received.”’ SIGUSR1; trap ‘echo “Signal 2 received.”’ SIGUSR2

以下是一些使用 trap 命令的最佳实践示例:

  1. 清理资源:
#!/bin/bash

cleanup() {
    echo "Cleaning up..."
    # 执行清理操作,例如关闭文件描述符、删除临时文件等
}
# 设置 EXIT 信号处理函数
trap cleanup EXIT
# 其他代码逻辑
  1. 记录错误日志:
#!/bin/bash

log_file="error.log"

# 定义错误处理函数,将错误信息记录到日志文件
handle_error() {
    echo "$(date): $BASH_COMMAND failed with exit code $?" >> "$log_file"
    exit 1
}

# 设置 ERR 信号处理函数
trap handle_error ERR

# 其他代码逻辑
  1. 忽略特定信号:
#!/bin/bash

# 忽略 CTRL+C 信号
trap '' INT

# 其他代码逻辑
  1. 优雅地处理脚本终止:
#!/bin/bash

cleanup() {
    echo "Performing cleanup..."
    # 清理操作
}

# 设置 EXIT 信号处理函数
trap cleanup EXIT

# 主要代码逻辑
echo "Running script..."

# 模拟脚本执行过程中的异常终止
if [[ "$1" == "error" ]]; then
    echo "Error occurred."
    exit 1
fi

echo "Script completed successfully."

这些示例演示了如何使用 trap 命令来处理不同的情况。根据具体需求,您可以根据自己的脚本逻辑和异常处理要求进行相应的定制。

  1. 其他类似命令
    除了 trap 命令,还有其他一些类似的接口可用于异常处理和信号捕获,如下所示:
  • kill: 用于向进程发送信号,可以用来模拟信号的发出。
  • psignal: 用于将信号名称转换为对应的描述字符串。
  • sigaction: 在更高级别上设置信号处理方式。
  1. 详细区别
    trap 命令与其他类似的接口相比具有以下区别:
  • trap 可以在 shell 脚本中定义信号处理函数,而 kill 和 psignal 主要用于发送和显示信号。
  • trap 可以在脚本中捕获和处理多种信号,而 sigaction 则提供更复杂的信号处理功能。
  • trap 可以捕获并处理特定事件(如 EXIT),而其他接口主要用于操作信号。
  1. 其他示例
#!/usr/bin/env bash

set -e

notes () {
    cat << EOF
======== WARM TIPS ========
Before you submit any github issue, please do the following check:
* make sure xxx
* make sure xxx
* check your internet connection if timeout happens
* check for potential port conflicts if you have local services
===========================
EOF
}

trap notes ERR
#!/bin/bash
 
# 函数定义:当脚本接收到信号时执行
trap_handler() {
  echo "脚本接收到信号,正在清理并退出..."
  # 在此处添加其他清理工作
  exit 0
}
 
# 设置trap
trap 'trap_handler' SIGINT SIGTERM
 
# 模拟长时间运行的进程
echo "按Ctrl+C或者使用kill命令发送SIGTERM信号试试看..."
while true; do
  sleep 1
done