linux 脚本解释

发布于:2025-07-19 ⋅ 阅读:(11) ⋅ 点赞:(0)

if [ $? -ne 0 ]; then

echo "错误: 无法关闭现有 Tomcat 实例,终止启动流程!" >&2

exit 1

fi

  1. $? 是shell中的特殊变量,表示上一个命令的退出状态码
  2. -ne 0 表示"不等于0"(在Unix/Linux中,0通常表示成功,非0表示错误)
  3. 如果前一个命令执行失败(返回非0),则执行花括号内的内容:
    • 输出错误信息到标准错误输出(stderr)
    • 使用exit 1终止脚本执行并返回错误状态码1

--------------------------------------------------------------------------------------------------

if [ -z "$1" ]; then
    echo "用法: $0 <TOMCAT_DIRECTORY>"
    exit 1
fi

具体解释如下:

  1. if [ -z "$1" ] 检查第一个参数($1)是否为空字符串

    • -z 测试字符串长度是否为0
    • $1 表示脚本的第一个参数
  2. 如果参数为空(即用户没有提供参数),则:

    • 输出用法提示:echo "用法: $0 <TOMCAT_DIRECTORY>"
      • $0 表示当前脚本的名称
    • 以状态码1退出脚本:exit 1 (1通常表示错误退出)

---------------------------------------------------------------------------------------------------

TOMCAT_DIR="$1"
TIMEOUT=10
TOMCAT=$(basename "${TOMCAT_DIR}")
CURRENT_USER=$(whoami)

以下是详细解释:

  1. TOMCAT_DIR="$1"

    • 将脚本的第一个参数($1)赋值给变量TOMCAT_DIR
    • 这个参数应该是Tomcat的安装目录路径
  2. TIMEOUT=10

    • 设置超时时间为10秒
    • 用于后续等待Tomcat关闭的时间控制
  3. TOMCAT=$(basename "${TOMCAT_DIR}")

    • 使用basename命令从目录路径中提取最后一级目录名
    • 例如:如果TOMCAT_DIR/opt/apache-tomcat-9.0.45,则TOMCAT值为apache-tomcat-9.0.45
  4. CURRENT_USER=$(whoami)

    • 获取当前执行脚本的用户名
    • 用于后续的权限检查和日志记录

-------------------------------------------------------------------------------------------------------------

# 检查目录和脚本存在性
[ ! -d "${TOMCAT_DIR}" ] && echo "错误: 目录不存在" && exit 1
[ ! -x "${TOMCAT_DIR}/bin/shutdown.sh" ] && echo "错误: shutdown.sh 不可执行" && exit 1

# 获取 Tomcat 主进程 PID(精确匹配)
get_pids() {
    ps -ef | grep "${TOMCAT}" | grep "org.apache.catalina.startup.Bootstrap" | grep -v grep | awk '{print $2}'
}

详细解释它们的功能和实现原理:

  1. 目录和脚本存在性检查部分:

    • [ ! -d "${TOMCAT_DIR}" ]:检查指定的Tomcat目录是否存在
      • -d测试目录是否存在
      • !表示逻辑非
    • [ ! -x "${TOMCAT_DIR}/bin/shutdown.sh" ]:检查shutdown.sh脚本是否存在且可执行
      • -x测试文件是否存在且可执行
    • 如果任一检查失败,会输出错误信息并以状态码1退出
  2. 获取Tomcat进程PID的函数:

    • ps -ef:列出所有进程的完整信息
    • grep "${TOMCAT}":过滤包含Tomcat目录名的进程
    • grep "org.apache.catalina.startup.Bootstrap":精确匹配Tomcat主类
    • grep -v grep:排除grep命令自身的进程
    • awk '{print $2}':提取第二列(即PID)
    • 这个函数通过多级过滤确保只获取真正的Tomcat主进程PID

----------------------------------------------------------------------------------------------------------------

# 初始检查进程
PIDS=$(get_pids)
if [ -z "${PIDS}" ]; then
    echo "Tomcat 未运行,无需关闭"
    exit 0
fi

echo "检测到 Tomcat 进程 (PID: ${PIDS})"

# 步骤1:尝试优雅关闭(忽略非关键错误,但记录)
echo "尝试优雅关闭..."
if ! ${TOMCAT_DIR}/bin/shutdown.sh; then
    echo "警告: shutdown.sh 执行失败(可能权限不足)"
fi

# 等待优雅关闭
echo "等待 ${TIMEOUT} 秒..."
sleep ${TIMEOUT}

详细解析:

  1. 初始进程检查:

    • 调用get_pids函数获取Tomcat进程PID
    • 如果PID为空(-z测试),输出提示并正常退出(exit 0)
    • 否则显示检测到的进程PID
  2. 优雅关闭流程:

    • 首先尝试执行Tomcat的shutdown.sh脚本
    • 使用if ! command结构捕获执行失败情况
    • 即使失败也仅输出警告而不终止(因为后续还有强制关闭逻辑)
  3. 等待处理:

    • 使用sleep命令等待预设的TIMEOUT时间(之前定义为10秒)
    • 这是给Tomcat完成正常关闭流程的时间窗口

----------------------------------------------------------------------------------------------------------

# 步骤2:检查是否仍有进程
PIDS=$(get_pids)
if [ -n "${PIDS}" ]; then
    echo "尝试正常终止进程 (PID: ${PIDS})"
    # 逐个检查并终止进程,记录失败
    for pid in ${PIDS}; do
        # 检查进程所有者
        PROCESS_OWNER=$(ps -o user= -p "${pid}" 2>/dev/null || echo "unknown")
        echo "进程 ${pid} 所有者: ${PROCESS_OWNER}"
        
        # 尝试终止进程
        if ! kill "${pid}" 2>/dev/null; then
            echo "错误: 无法终止进程 ${pid}(权限不足,当前用户 ${CURRENT_USER} 无法操作 ${PROCESS_OWNER} 的进程)"
            exit 1  # 权限不足时立即报错退出
        fi
    done

    # 等待后再次检查
    sleep 5
    PIDS=$(get_pids)
    if [ -n "${PIDS}" ]; then
        echo "尝试强制终止进程 (PID: ${PIDS})"
        for pid in ${PIDS}; do
            if ! kill -9 "${pid}" 2>/dev/null; then
                echo "错误: 无法强制终止进程 ${pid}(权限不足)"
                exit 1  # 权限不足时立即报错退出
            fi
        done
    fi
fi

# 最终检查
PIDS=$(get_pids)
if [ -z "${PIDS}" ]; then
    echo "Tomcat 已成功关闭"
else
    echo "错误: 仍有进程未关闭 (PID: ${PIDS})"
    exit 1
fi

echo "========== 关闭完成 =========="
exit 0

详细解析:

  1. 进程二次检查:

    • 使用-n测试检查是否仍有存活的Tomcat进程
    • 如果有则进入强制终止流程
  2. 分级终止策略:

    • 先尝试普通kill命令(SIGTERM信号)
    • 检查每个进程的所有者(使用ps -o user= -p PID)
    • 对kill失败的情况立即报错退出(权限问题)
  3. 强制终止阶段:

    • 等待5秒后再次检查
    • 对仍然存活的进程使用kill -9(SIGKILL信号)
    • 同样处理权限错误情况
  4. 最终状态确认:

    • 最后一次检查进程状态
    • 根据结果输出成功/失败信息
    • 返回相应的退出状态码(0成功/1失败)

这个设计体现了完善的进程管理策略:

  • 分级处理(先优雅后强制)
  • 完善的错误检查和权限验证
  • 明确的进程状态跟踪
  • 清晰的执行反馈

代码中几个关键Shell技巧:

  • 2>/dev/null屏蔽错误输出
  • ps -o user=只输出用户名列
  • || echo "unknown"错误处理
  • 多级if [ -n/-z ]条件测试

网站公告

今日签到

点亮在社区的每一天
去签到