Shell脚本如何实现事件驱动

wen 实用脚本 1

本文目录导读:

Shell脚本如何实现事件驱动

  1. 使用 inotifywait 监控文件系统事件
  2. 使用 trap 处理信号事件
  3. 使用命名管道实现异步事件
  4. 使用 socat 实现网络事件驱动
  5. 事件循环 + 超时机制
  6. 使用 xargs 实现并行事件处理
  7. 完整的消息队列事件驱动示例

Shell脚本本身不是事件驱动架构的原生语言,但可以通过多种机制模拟事件驱动模式,以下是几种主流实现方法:

使用 inotifywait 监控文件系统事件

#!/bin/bash
# 监控目录变化
WATCH_DIR="/path/to/watch"
inotifywait -m -r -e create -e modify -e delete --format '%w%f %e' "$WATCH_DIR" |
while read file event; do
    case "$event" in
        CREATE)
            echo "文件创建: $file"
            # 处理创建事件
            ;;
        MODIFY)
            echo "文件修改: $file"
            # 处理修改事件
            ;;
        DELETE)
            echo "文件删除: $file"
            # 处理删除事件
            ;;
    esac
done

使用 trap 处理信号事件

#!/bin/bash
# 定义信号处理函数
cleanup() {
    echo "收到终止信号,清理资源..."
    # 清理操作
    exit 0
}
reload_config() {
    echo "重新加载配置..."
    # 重新加载配置
}
# 注册信号处理器
trap cleanup SIGINT SIGTERM
trap reload_config SIGHUP
# 主循环
echo "服务启动,PID: $$"
while true; do
    # 主业务逻辑
    sleep 1
done

使用命名管道实现异步事件

#!/bin/bash
PIPE="/tmp/event-pipe"
mkfifo "$PIPE" 2>/dev/null
# 事件分发器
event_loop() {
    while true; do
        if read event < "$PIPE"; then
            handle_event "$event"
        fi
    done
}
# 事件处理器
handle_event() {
    local event="$1"
    case "$event" in
        "user_login")
            echo "用户登录事件触发"
            # 执行登录逻辑
            ;;
        "data_update")
            echo "数据更新事件触发"
            # 执行更新逻辑
            ;;
        "shutdown")
            echo "关闭事件,退出程序"
            exit 0
            ;;
    esac
}
# 事件发送函数
send_event() {
    echo "$1" > "$PIPE" &
}
# 启动事件循环
event_loop &
# 模拟发送事件
send_event "user_login"
sleep 2
send_event "data_update"
sleep 2
send_event "shutdown"
wait
rm -f "$PIPE"

使用 socat 实现网络事件驱动

#!/bin/bash
PORT=8080
# 接收HTTP请求事件
socat TCP-LISTEN:$PORT,fork EXEC:./request_handler.sh
# request_handler.sh 内容
#!/bin/bash
read request
echo "接收到请求: $request"
# 解析请求并处理
echo -e "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nEvent processed"

事件循环 + 超时机制

#!/bin/bash
# 事件队列
declare -A EVENT_QUEUE
EVENT_COUNTER=0
# 注册事件
register_event() {
    local event_name="$1"
    local callback="$2"
    EVENT_QUEUE["$event_name"]="$callback"
}
# 触发事件
trigger_event() {
    local event_name="$1"
    local callback="${EVENT_QUEUE[$event_name]}"
    if [ -n "$callback" ]; then
        $callback "$@"
    else
        echo "未注册的事件: $event_name"
    fi
}
# 事件循环
event_loop() {
    local timeout="$1"
    while true; do
        # 检查是否有待处理事件
        # 这里可以是文件监控、定时器或其他
        # 模拟超时
        if [ "$EVENT_COUNTER" -ge "$timeout" ]; then
            trigger_event "timeout"
            break
        fi
        sleep 1
        ((EVENT_COUNTER++))
    done
}
# 定义事件处理器
on_timeout() {
    echo "超时事件触发,退出循环"
}
# 注册事件
register_event "timeout" "on_timeout"
# 启动事件循环(5秒超时)
event_loop 5

使用 xargs 实现并行事件处理

#!/bin/bash
# 事件处理函数
process_event() {
    local event="$1"
    echo "处理事件: $event (PID: $$)"
    sleep 2
}
# 事件源
generate_events() {
    for i in {1..5}; do
        echo "event_$i"
    done
}
# 并行处理事件(最多3个并行)
generate_events | xargs -P3 -I{} bash -c 'process_event "$@"' _ {}

完整的消息队列事件驱动示例

#!/bin/bash
# 事件驱动框架
EVENT_HANDLERS=()
MESSAGE_QUEUE="/tmp/msg_queue"
# 初始化
init() {
    mkfifo "$MESSAGE_QUEUE" 2>/dev/null
    echo "事件驱动框架初始化完成"
}
# 注册事件处理器
on() {
    local event="$1"
    local handler="$2"
    EVENT_HANDLERS["$event"]="$handler"
}
# 发送事件
emit() {
    local event="$1"
    shift
    local data="$@"
    echo "$event|$data" > "$MESSAGE_QUEUE" &
}
# 事件循环
start() {
    echo "启动事件循环..."
    while true; do
        if read line < "$MESSAGE_QUEUE"; then
            IFS='|' read -r event data <<< "$line"
            handler="${EVENT_HANDLERS[$event]}"
            if [ -n "$handler" ]; then
                echo "处理事件: $event"
                $handler "$data"
            fi
        fi
    done
}
# 定义事件处理器
on_user_login() {
    echo "用户登录: $1"
    # 执行登录后的逻辑
}
on_data_received() {
    echo "收到数据: $1"
    # 处理数据
}
on_error() {
    echo "错误: $1"
    # 错误处理
}
# 主程序
init
on "user_login" "on_user_login"
on "data_received" "on_data_received"
on "error" "on_error"
# 启动事件循环(后台运行)
start &
# 发送测试事件
sleep 1
emit "user_login" "Alice"
sleep 1
emit "data_received" "some_data"
sleep 1
emit "error" "connection_timeout"
# 等待处理完成
sleep 3
kill %1 2>/dev/null
rm -f "$MESSAGE_QUEUE"
  1. 使用 inotifywait:适合文件系统监控场景
  2. 使用 trap:处理系统信号事件
  3. 命名管道:实现进程间通信的事件队列
  4. socat/nc:网络事件驱动
  5. 并行处理:使用 xargs -P 实现并发
  6. 状态机:结合 case 语句实现状态转换

选择哪种方法取决于具体需求:文件监控场景首选 inotifywait,进程间通信推荐命名管道,网络服务用 socat,简单的事件处理用 trap

抱歉,评论功能暂时关闭!