Shell脚本如何顺序执行依赖任务

wen 实用脚本 1

Shell脚本如何顺序执行依赖任务:从基础到高级的完整指南

目录导读

  1. 什么是依赖任务与顺序执行?
  2. Shell脚本顺序执行的基础方法
  3. 处理任务依赖的常见场景
  4. 高级技巧:并行中的顺序控制
  5. 实战案例:部署脚本中的依赖链
  6. 常见问题与解决方案(问答)

什么是依赖任务与顺序执行?

在实际的运维或开发工作中,我们经常遇到这样的场景:任务B必须等任务A完成后才能执行,任务C又依赖任务B的结果,这种任务间的前置关系叫做“依赖任务”,Shell脚本是处理这类场景最直接的工具,它通过简单的命令排列、条件判断和循环控制,就能实现精准的顺序执行。

Shell脚本如何顺序执行依赖任务

编译代码必须先下载依赖包,部署服务必须先停止旧进程,忽略依赖顺序会导致脚本崩溃或产生不可预测的后果。

Shell脚本顺序执行的基础方法

1 使用分号和换行符

最简单的顺序执行就是直接将命令按顺序写在一起:

echo "步骤1:检查环境"
check_env.sh
echo "步骤2:下载依赖"
download_deps.sh
echo "步骤3:编译项目"
build.sh

Shell会从上到下依次执行每行命令,但这种方式无法处理前一步失败的情况。

2 使用逻辑控制符

利用&&和可以实现有条件的顺序执行:

check_env.sh && download_deps.sh && build.sh

只有前一个命令成功(退出码为0),才会执行下一个,如果失败,后续步骤自动跳过。

3 使用if条件判断

更清晰的依赖处理方式:

if check_env.sh; then
    echo "环境检查通过"
    if download_deps.sh; then
        build.sh
    else
        echo "下载依赖失败,终止"
        exit 1
    fi
else
    echo "环境检查失败"
    exit 1
fi

处理任务依赖的常见场景

顺序无依赖

多个独立任务,但要求按顺序逐个执行:

for task in "初始化配置" "安装包" "设置权限"; do
    echo "执行:$task"
    eval "${task// /_}.sh" || exit 1
done

线性依赖链

任务A→任务B→任务C,每个必须成功:

function run_chain() {
    task_a || return 1
    task_b || return 1
    task_c || return 1
}

部分依赖(DAG结构)

任务C依赖A和B,但A和B可以并行执行,这里先用顺序方式处理:

task_a
task_b
# 确保两者都完成后
if [ $? -eq 0 ]; then
    task_c
fi

高级技巧:并行中的顺序控制

当需要提升效率时,可以使用后台执行与wait结合:

task_a &  # 后台运行
task_b &  # 后台运行
wait      # 等待所有后台进程完成
# 此时A和B都已完成
task_c    # 开始依赖任务

如果需要更精细的控制,可以使用临时文件标记完成状态:

# 任务A完成时创建标记文件
task_a && touch /tmp/done_a &
task_b && touch /tmp/done_b &
# 等待两个标记文件出现
while [ ! -f /tmp/done_a ] || [ ! -f /tmp/done_b ]; do
    sleep 1
done
task_c

实战案例:部署脚本中的依赖链

假设我们要部署一个Node.js应用,依赖顺序为:

  1. 安装系统依赖(git,nvm)
  2. 克隆仓库
  3. 安装npm包
  4. 运行测试
  5. 启动服务

完整脚本示例:

#!/bin/bash
set -e  # 任何错误立即退出
DEPLOY_DIR="/var/www/app"
LOG_FILE="/var/log/deploy.log"
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}
log "开始部署流程"
# 步骤1:系统准备
if command -v git &>/dev/null && command -v node &>/dev/null; then
    log "系统环境已就绪"
else
    log "安装系统依赖..."
    apt-get update && apt-get install -y git curl
    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
fi
# 步骤2:克隆(依赖步骤1)
if [ ! -d "$DEPLOY_DIR" ]; then
    log "克隆仓库..."
    git clone https://example.com/repo.git $DEPLOY_DIR
else
    log "拉取最新代码..."
    cd $DEPLOY_DIR && git pull
fi
# 步骤3:安装npm(依赖步骤2)
cd $DEPLOY_DIR
log "安装npm依赖..."
npm ci
# 步骤4:测试(依赖步骤3)
log "运行测试..."
npm test
# 步骤5:启动(依赖步骤4)
log "启动服务..."
pm2 restart app.js 2>/dev/null || pm2 start app.js
log "部署完成"

常见问题与解决方案(问答)

问:如果依赖任务执行失败,如何做重试机制?

答:使用循环与计数器。

MAX_RETRIES=3
RETRY_COUNT=0
until [ $RETRY_COUNT -ge $MAX_RETRIES ]; do
    dangerous_task && break
    RETRY_COUNT=$((RETRY_COUNT+1))
    echo "重试 $RETRY_COUNT/$MAX_RETRIES"
    sleep 5
done
if [ $RETRY_COUNT -ge $MAX_RETRIES ]; then
    echo "任务失败,已重试$MAX_RETRIES次"
    exit 1
fi

问:如何确保脚本中某些步骤必须按顺序,而其他步骤可以并行?

答:使用wait控制点,如上述高级技巧所示,或者用flock文件锁实现跨进程同步:

# 步骤A和B并行,步骤C等待两者
(step_a && touch /tmp/step_a.done) &
(step_b && touch /tmp/step_b.done) &
wait
step_c  # 此时必等A和B完成

问:Shell脚本中如何判断依赖是否已满足?

答:检查前置任务生成的文件、进程状态或返回值,常用方法:

  • 检查文件是否存在:[ -f /tmp/flag ]
  • 检查进程运行:pgrep -x "process_name"
  • 检查退出码:command || echo "失败"

问:顺序执行时,如果某一任务耗时很久,如何显示进度?

答:在长时间任务中加入进度指示:

long_task &
PID=$!
while kill -0 $PID 2>/dev/null; do
    echo -n "."
    sleep 1
done
echo "完成"

更专业的工具是pvprogress命令,但需要额外安装。

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