本文目录导读:

Shell脚本实现任务队列有多种方式,从简单到复杂,我为你介绍几种常用方案:
基于文件的任务队列(最简单)
生产者-消费者模式
#!/bin/bash
QUEUE_DIR="/tmp/task_queue"
mkdir -p "$QUEUE_DIR"
# 生产者:添加任务
add_task() {
local task_id=$(date +%s%N)
local task_file="$QUEUE_DIR/$task_id"
# 写入任务内容
cat > "$task_file" << EOF
{
"id": "$task_id",
"command": "$1",
"created_at": "$(date)"
}
EOF
echo "Task $task_id added"
}
# 消费者:处理任务
process_tasks() {
while true; do
# 获取最早的任务文件
local task_file=$(ls -t "$QUEUE_DIR" 2>/dev/null | tail -1)
if [[ -n "$task_file" ]]; then
local full_path="$QUEUE_DIR/$task_file"
echo "Processing: $task_file"
# 执行任务(使用source加载任务内容)
source "$full_path"
eval "$command"
# 处理完成后删除任务文件
rm "$full_path"
echo "Completed: $task_file"
fi
sleep 1
done
}
# 使用示例
add_task "echo 'Hello World'"
add_task "sleep 2; echo 'Task 2 done'"
add_task "date"
# 启动消费者(在后台运行)
process_tasks &
基于命名管道的任务队列
#!/bin/bash
PIPE="/tmp/task_pipe"
LOCK_FILE="/tmp/task_pipe.lock"
# 初始化管道
init_pipe() {
if [[ ! -p "$PIPE" ]]; then
mkfifo "$PIPE"
fi
}
# 添加任务到队列
enqueue() {
echo "$1" >> "$PIPE"
}
# 从队列取出任务
dequeue() {
local task=""
# 使用文件锁确保原子操作
(
flock -x 200
# 读取一个任务
read -r task < "$PIPE"
if [[ -n "$task" ]]; then
echo "$task"
fi
) 200>"$LOCK_FILE"
}
# 工作进程
worker() {
while true; do
local task=$(dequeue)
if [[ -n "$task" ]]; then
echo "Worker $$ executing: $task"
eval "$task"
echo "Worker $$ completed: $task"
fi
sleep 0.1
done
}
# 使用示例
init_pipe
# 添加任务
for i in {1..5}; do
enqueue "echo 'Task $i: $(date)'"
done
# 启动2个工作进程
worker &
worker &
# 等待所有任务完成
wait
带有并发控制的队列
#!/bin/bash
MAX_CONCURRENT=3
QUEUE_FILE="/tmp/queue.txt"
RUNNING_FILE="/tmp/running.txt"
# 初始化队列
init_queue() {
> "$QUEUE_FILE"
> "$RUNNING_FILE"
}
# 添加任务
add_to_queue() {
echo "$1" >> "$QUEUE_FILE"
}
# 获取任务计数
get_queue_count() {
wc -l < "$QUEUE_FILE" 2>/dev/null || echo 0
}
# 获取运行中的任务数
get_running_count() {
wc -l < "$RUNNING_FILE" 2>/dev/null || echo 0
}
# 执行任务
execute_task() {
local task="$1"
local task_id=$(date +%s%N)
# 记录运行中的任务
echo "$task_id:$task" >> "$RUNNING_FILE"
echo "Starting: $task"
# 执行任务
eval "$task"
# 从运行列表中移除
sed -i "/^$task_id:/d" "$RUNNING_FILE"
echo "Completed: $task"
}
# 调度器
scheduler() {
while true; do
local queue_count=$(get_queue_count)
local running_count=$(get_running_count)
# 检查是否有空闲槽位和待处理任务
if [[ $running_count -lt $MAX_CONCURRENT && $queue_count -gt 0 ]]; then
# 获取第一个任务
local task=$(head -1 "$QUEUE_FILE")
if [[ -n "$task" ]]; then
# 从队列中移除
sed -i '1d' "$QUEUE_FILE"
# 在子进程中执行
(execute_task "$task") &
fi
fi
sleep 0.5
done
}
# 使用示例
init_queue
# 添加一些耗时任务
add_to_queue "sleep 2; echo 'Task 1 done'"
add_to_queue "sleep 3; echo 'Task 2 done'"
add_to_queue "sleep 1; echo 'Task 3 done'"
add_to_queue "sleep 4; echo 'Task 4 done'"
add_to_queue "sleep 2; echo 'Task 5 done'"
# 启动调度器
scheduler &
# 等待完成
sleep 10
echo "All tasks dispatched"
带有资源限制的队列系统
#!/bin/bash
# 任务队列类
declare -A TASK_QUEUE
TASK_COUNTER=0
MAX_TASKS=10
MAX_MEMORY=500 # MB
# 检查系统资源
check_resources() {
local memory_usage=$(free -m | awk 'NR==2{print $3}')
local cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
if [[ $memory_usage -gt $MAX_MEMORY ]]; then
return 1 # 内存不足
fi
if [[ $(echo "$cpu_usage > 80" | bc) -eq 1 ]]; then
return 1 # CPU负载过高
fi
return 0
}
# 添加任务
add_task() {
local priority=${2:-5} # 默认优先级5
local task_id=$((++TASK_COUNTER))
TASK_QUEUE[$task_id]="$1:$priority"
# 按优先级排序
sort_tasks
}
# 排序任务(按优先级)
sort_tasks() {
# 创建临时排序文件
local temp_file=$(mktemp)
for id in "${!TASK_QUEUE[@]}"; do
IFS=':' read -r task priority <<< "${TASK_QUEUE[$id]}"
echo "$priority $id $task" >> "$temp_file"
done
sort -n "$temp_file" | while read line; do
echo "$line"
done
rm "$temp_file"
}
# 获取最高优先级任务
get_next_task() {
local highest_priority=999
local next_task_id=""
local next_command=""
for id in "${!TASK_QUEUE[@]}"; do
IFS=':' read -r task priority <<< "${TASK_QUEUE[$id]}"
if [[ $priority -lt $highest_priority ]]; then
highest_priority=$priority
next_task_id=$id
next_command=$task
fi
done
if [[ -n "$next_task_id" ]]; then
echo "$next_task_id:$next_command"
fi
}
# 执行任务
run_task() {
local command="$1"
if check_resources; then
echo "Executing: $command"
eval "$command"
return $?
else
echo "Resource limit reached, waiting..."
sleep 2
run_task "$command" # 重试
fi
}
# 任务管理器
task_manager() {
while true; do
local next_task=$(get_next_task)
if [[ -n "$next_task" ]]; then
local task_id="${next_task%%:*}"
local command="${next_task#*:}"
# 删除任务
unset TASK_QUEUE[$task_id]
# 执行任务
run_task "$command"
echo "Task $task_id completed"
fi
sleep 1
done
}
# 使用示例
add_task "echo 'High priority task'" 1
add_task "sleep 2; echo 'Normal task'"
add_task "sleep 1; echo 'Low priority task'" 10
# 启动任务管理器
task_manager &
企业级队列管理(带状态记录)
#!/bin/bash
# 队列数据库(使用文件模拟)
QUEUE_DB="/tmp/queue.db"
STATUS_DB="/tmp/queue_status.db"
# 初始化数据库
init_db() {
echo "task_id|status|command|created_at|completed_at" > "$QUEUE_DB"
echo "idle" > "$STATUS_DB"
}
# 添加任务到数据库
db_add_task() {
local task_id=$(uuidgen 2>/dev/null || date +%s%N)
local command="$1"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "$task_id|pending|$command|$timestamp|" >> "$QUEUE_DB"
echo "$task_id"
}
# 更新任务状态
db_update_status() {
local task_id="$1"
local new_status="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
# 使用临时文件更新
local temp_file=$(mktemp)
while IFS='|' read -r id status command created completed; do
if [[ "$id" == "$task_id" ]]; then
if [[ "$new_status" == "completed" || "$new_status" == "failed" ]]; then
echo "$id|$new_status|$command|$created|$timestamp"
else
echo "$id|$new_status|$command|$created|$completed"
fi
else
echo "$id|$status|$command|$created|$completed"
fi
done < "$QUEUE_DB" > "$temp_file"
mv "$temp_file" "$QUEUE_DB"
}
# 获取待处理任务
get_pending_tasks() {
awk -F'|' '$2 == "pending" {print $0}' "$QUEUE_DB"
}
# 任务执行器
task_executor() {
local worker_id=$1
echo "Worker $worker_id started"
while true; do
# 获取当前系统状态
local queue_status=$(cat "$STATUS_DB")
if [[ "$queue_status" == "running" ]]; then
# 获取待处理任务
local pending_tasks=$(get_pending_tasks)
if [[ -n "$pending_tasks" ]]; then
# 取第一个任务
local task=$(echo "$pending_tasks" | head -1)
local task_id=$(echo "$task" | cut -d'|' -f1)
local command=$(echo "$task" | cut -d'|' -f3)
# 更新状态为运行中
db_update_status "$task_id" "running"
echo "Worker $worker_id executing: $command"
# 执行任务
if eval "$command"; then
db_update_status "$task_id" "completed"
echo "Worker $worker_id completed task $task_id"
else
db_update_status "$task_id" "failed"
echo "Worker $worker_id failed task $task_id"
fi
fi
fi
sleep 2
done
}
# 队列控制器
queue_controller() {
echo "Queue controller started"
# 添加示例任务
for i in {1..5}; do
db_add_task "echo 'Task $i: $(date)'; sleep 2"
done
# 设置队列为运行状态
echo "running" > "$STATUS_DB"
# 启动3个工作进程
for i in {1..3}; do
task_executor "$i" &
done
# 监控队列状态
while true; do
local pending=$(get_pending_tasks | wc -l)
local total=$(wc -l < "$QUEUE_DB")
echo "Queue status: $pending pending / $((total - 1)) total"
if [[ $pending -eq 0 ]]; then
echo "All tasks completed"
echo "idle" > "$STATUS_DB"
break
fi
sleep 5
done
}
# 使用示例
init_db
queue_controller
使用建议
- 简单场景:使用基于文件的队列(方法1)
- 并发控制:使用命名管道方案(方法2)
- 资源限制:使用带有资源控制的队列(方法3-4)
- 企业级应用:使用带数据库记录的方案(方法5)
这些方案可以根据你的具体需求进行修改和扩展,需要我详细解释某个具体实现吗?