Shell脚本编程(bash)简述

目录

基础

脚本编写规范

运行方式

语法

变量

条件判断

循环

示例

免密登录配置

远程执行命令

批量同步配置文件

集群一键启动/停止脚本


针对集群运维

Shell教程

基础

脚本编写规范

①脚本文件后缀:通常以.sh结尾(并非强制,但便于识别)

②首行解释器:#!/bin/bash(固定写法,告诉系统用 bash 解释器执行脚本)

③注释规范

  • 单行注释:# 注释内容(用于解释单行命令或变量含义)

  • 多行注释:

    方式1:多行单注释(适合少量多行)

    这是一个大数据批量处理脚本

    功能:同步原始数据并进行格式转换

    方式2:利用here文档(适合大量多行注释)

    : <<EOF
    这是多行注释内容

    1. 脚本作者:XXX
    2. 适用场景:Hadoop数据预处理
    3. 执行条件:需拥有bigdata目录读写权限
      EOF

运行方式

①赋予执行权限:

复制代码
# 方式1:给当前用户添加执行权限(推荐,最安全)
chmod u+x bigdata_task.sh
# 方式2:给所有用户添加执行权限(适合公共脚本)
chmod a+x bigdata_task.sh
# 方式3:给当前用户读+写+执行权限,其他用户读+执行权限(精细权限控制)
chmod 755 bigdata_task.sh
# 权限说明:数字对应r(读=4)、w(写=2)、x(执行=1),7=4+2+1,5=4+1

②运行脚本:

复制代码
# 方式1:相对路径运行(推荐,需先赋予执行权限)
./bigdata_task.sh
# 适用:脚本在当前工作目录下

# 方式2:绝对路径运行(推荐,需先赋予执行权限)
/opt/bigdata/scripts/bigdata_task.sh
# 适用:脚本在固定目录,便于定时任务调用

# 方式3:通过解释器直接运行(无需赋予执行权限)
bash bigdata_task.sh
# 或
sh bigdata_task.sh
# 适用:临时运行脚本,无需修改权限

# 方式4:在当前shell环境中运行(用.或source)
. ./bigdata_task.sh
# 或
source ./bigdata_task.sh
# 适用:脚本中定义的变量需要在当前shell中生效(如配置环境变量的脚本)

语法

变量

①变量的定义:

  1. 变量名=值(等号前后无空格,不能包含特殊字符)

  2. 变量名只能包含字母、数字、下划线,不能以数字开头

  3. 变量值如果包含空格,需要用双引号包裹

    #!/bin/bash

    定义集群运维常用变量(贴合实际场景)

    HADOOP_HOME="/opt/hadoop" # Hadoop安装目录(无空格,直接定义)
    SPARK_HOME="/opt/spark-3.3.0" # Spark安装目录
    CLUSTER_NODES="master slave1 slave2 slave3" # 集群节点列表(有空格,用双引号包裹也可以)
    LOG_DIR="/bigdata/ops/logs" # 运维日志目录
    DATA_DIR="/bigdata/data" # 数据存储目录

②变量的使用:

  • 调用变量时,在变量名前加 ,推荐用 {变量名} 的格式,更规范。

    #!/bin/bash

    定义变量

    HADOOP_HOME="/opt/hadoop"
    LOG_DIR="/bigdata/ops/logs"

    使用变量

    echo "Hadoop安装目录:HADOOP_HOME" # 简单调用 echo "运维日志目录:{LOG_DIR}" # 推荐格式,更规范
    echo "HDFS启动脚本路径:${HADOOP_HOME}/sbin/start-dfs.sh" # 拼接路径(核心用法)

③特殊变量:

  • $0:脚本自身文件名

  • 1、2...:接收脚本运行时传入的参数

    #!/bin/bash

    脚本名称:check_node.sh

    运行方式:./check_node.sh slave1 20251221

    echo "要检查的节点名称:1" # 接收第一个参数(slave1) echo "检查日期:2" # 接收第二个参数(20251221)
    echo "脚本文件名:0" # 0 固定表示脚本本身的名字(check_node.sh)

  • {n}:第 3\~9 个位置参数(超过 9 个需用{10}格式)

  • $#:位置参数的总个数(统计传入参数的数量)

  • $*:所有位置参数的集合,将所有参数视为一个整体(命令用双引号包裹时生效)

  • $@:所有位置参数的集合,将所有参数中每个参数视为独立个体(用双引号包裹时生效)

    #!/bin/bash

    示例:区分*和@

    echo "===== 遍历$*(视为整体) ====="
    for arg in "*"; do echo "参数:arg" # 仅输出1行:参数:a b c
    done

    echo "===== 遍历$@(视为独立个体,推荐) ====="
    for arg in "@"; do echo "参数:arg" # 输出3行:参数:a;参数:b;参数:c
    done

  • ?:获取上一条命令的执行结果,? 只有两个值:0 表示上一条命令执行成功,非0 表示执行失败,这是运维脚本中 "判断命令是否生效"的用法。

    #!/bin/bash

    尝试启动HDFS

    /opt/hadoop/sbin/start-dfs.sh

    判断启动是否成功

    if [ $? -eq 0 ]; then
    echo "HDFS启动成功!"
    else
    echo "HDFS启动失败!"
    fi

条件判断

①语法格式:

复制代码
# 格式1:test + 空格 + 条件表达式(空格不可省略,用于区分命令和表达式)
#  Shell 内置的条件检测命令,无需依赖特殊解释器
test -f "$DATA_FILE"

# 格式2:[ + 空格 + 条件表达式 + 空格 + ](推荐,更直观,注意前后必须有空格)
[ -f "$DATA_FILE" ]

# 格式3:[[ + 条件表达式 + ]](bash专属,支持正则匹配、逻辑运算更简洁)
[[ "$DATA_DATE" =~ ^[0-9]{8}$ ]]


# 写法
if [ 条件表达式 ]; then
    # 条件满足时,执行的命令(可以写多行)
    命令1
    命令2
else
    # 条件不满足时,执行的命令(可以写多行)
    命令3
    命令4
fi

②常用判断条件:

判断类型 条件表达式 含义
文件判断 [ -f "$file" ] 判断是否为普通文件
文件判断 [ -d "$dir" ] 判断是否为目录
文件判断 [ -e "$path" ] 判断文件 / 目录是否存在
文件判断 [ -r "$file" ] 判断是否有读权限(读取数据文件时校验)
文件判断 [ -w "$file" ] 判断是否有写权限(写入数据时校验)
字符串判断 [ "\(str1" = "\)str2" ] 判断两个字符串相等(注意等号前后有空格)
字符串判断 [ "\(str1" != "\)str2" ] 判断两个字符串不相等
字符串判断 [ -n "$str" ] 判断字符串非空(校验参数是否传入)
字符串判断 [ -z "$str" ] 判断字符串为空
数字判断 [ num1 -eq num2 ] 等于(equal)
数字判断 [ num1 -ne num2 ] 不等于(not equal)
数字判断 [ num1 -gt num2 ] 大于(greater than)
数字判断 [ num1 -lt num2 ] 小于(less than)
数字判断 [ num1 -ge num2 ] 大于等于(greater or equal)
数字判断 [ num1 -le num2 ] 小于等于(less or equal)
逻辑运算 [条件 1] && [ 条件 2 ] 逻辑与(两个条件都成立)
逻辑运算 [条件 1] || [ 条件 2 ] 逻辑或(两个条件有一个成立)
逻辑运算 [! 条件] 逻辑非(条件不成立)
复制代码
#!/bin/bash
# 条件判断实战:集群环境前置检查
HADOOP_HOME="/opt/hadoop"
LOG_DIR="/bigdata/ops/logs"
DISK_USAGE=86  # 模拟磁盘使用率

# 1. 判断Hadoop目录是否存在
if [ -d "${HADOOP_HOME}" ]; then
    echo "Hadoop目录存在:${HADOOP_HOME}"
else
    echo "错误:Hadoop目录不存在!"
    exit 1  # 退出脚本,不再执行后续内容
fi

# 2. 判断日志目录是否存在,不存在则创建
if [ ! -d "${LOG_DIR}" ]; then  # ! 表示"非",即目录不存在时
    echo "日志目录不存在,正在创建:${LOG_DIR}"
    mkdir -p "${LOG_DIR}"  # -p 递归创建目录
fi

# 3. 判断磁盘使用率是否超标(大于85%)
if [ ${DISK_USAGE} -gt 85 ]; then
    echo "警告:磁盘使用率超标(${DISK_USAGE}%),请及时清理!"
else
    echo "磁盘使用率正常(${DISK_USAGE}%)"
fi

循环

①for循环:

  • 基础格式:

    格式1:遍历固定列表(适合集群节点批量操作)

    for 变量名 in 列表内容; do
    # 循环执行的命令
    命令
    done

    格式2:数字循环(适合按序号遍历分区/任务)

    for ((i=1; i<=5; i++)); do
    # 循环执行的命令
    命令
    done

    #!/bin/bash

    批量检查所有从节点的DataNode进程

    定义节点列表

    nodes=("slave1" "slave2" "slave3")

    遍历节点列表

    for node in "{nodes[@]}"; do # "{nodes[@]}" 表示遍历所有节点
    echo "===== 正在检查节点:{node} =====" # 远程执行命令,检查DataNode进程 ssh root@{node} "jps | grep DataNode | grep -v grep"
    # 判断进程是否存在
    if [ ? -eq 0 ]; then echo "节点{node}:DataNode进程正常"
    else
    echo "节点${node}:DataNode进程缺失(异常)"
    fi
    done

②while循环:

  • 基础格式

    while [ 条件表达式 ]; do
    # 条件满足时,循环执行的命令
    命令
    sleep 10 # 休眠10秒,避免循环过快占用资源
    done

    特殊:无限循环(适合集群监控脚本)

    while true; do
    # 持续执行的命令(如监控进程状态)
    命令
    sleep 60 # 每分钟检查一次
    done

    #!/bin/bash

    监控NameNode进程,异常时打印告警

    while true; do
    # 检查NameNode进程
    jps | grep NameNode | grep -v grep
    if [ ? -ne 0 ]; then echo "[(date +'%Y-%m-%d %H:%M:%S')] 告警:NameNode进程异常退出!"
    else
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] NameNode进程运行正常"
    fi
    sleep 60 # 每分钟检查一次
    done

示例

免密登录配置

复制代码
# 1. 在主节点生成RSA密钥对(一路回车,不设置密钥密码)
ssh-keygen -t rsa -b 4096  # -b 4096提升密钥安全性

# 2. 将公钥批量分发到所有集群节点(包括主节点自身)
# 定义节点列表(替换为你的集群节点)
nodes=("master" "slave1" "slave2" "slave3")
for node in "${nodes[@]}"; do
    ssh-copy-id -i ~/.ssh/id_rsa.pub root@${node}
done

# 3. 验证免密登录(无需密码即可登录从节点)
ssh slave1

远程执行命令

复制代码
# 场景1:批量检查所有从节点的DataNode进程
nodes=("slave1" "slave2" "slave3")
for node in "${nodes[@]}"; do
    echo "===== 节点${node}进程状态 ====="
    ssh root@${node} "jps | grep DataNode | grep -v grep"
done

# 场景2:批量在从节点创建数据目录
for node in "${nodes[@]}"; do
    ssh root@${node} "mkdir -p /bigdata/data /bigdata/logs && chmod 755 /bigdata"
done

# 场景3:批量查看从节点磁盘使用率
for node in "${nodes[@]}"; do
    echo "===== 节点${node}磁盘使用情况 ====="
    ssh root@${node} "df -h | grep /bigdata"
done

批量同步配置文件

复制代码
#!/bin/bash
# 批量同步Hadoop配置文件
SRC_DIR="/opt/hadoop/conf"  # 主节点配置源目录
DST_DIR="/opt/hadoop/conf"  # 从节点配置目标目录
nodes=("slave1" "slave2" "slave3")  # 从节点列表

for node in "${nodes[@]}"; do
    echo "===== 同步配置到节点${node} ====="
    # 步骤1:备份从节点原有配置
    BACKUP_DIR="${DST_DIR}_backup_$(date +%Y%m%d%H%M%S)"
    ssh root@${node} "mkdir -p ${BACKUP_DIR} && cp -r ${DST_DIR}/* ${BACKUP_DIR}/"
    
    # 步骤2:批量同步配置文件(-r 递归复制,-p 保留权限)
    scp -rp "${SRC_DIR}"/* root@${node}:"${DST_DIR}/"
    
    # 步骤3:验证配置一致性(对比MD5值)
    SRC_MD5=$(md5sum "${SRC_DIR}/core-site.xml" | awk '{print $1}')
    DST_MD5=$(ssh root@${node} "md5sum ${DST_DIR}/core-site.xml | awk '{print \$1}'")
    if [ "${SRC_MD5}" = "${DST_MD5}" ]; then
        echo "节点${node}配置同步成功,一致性验证通过"
    else
        echo "节点${node}配置同步失败,已自动回滚到${BACKUP_DIR}"
        ssh root@${node} "cp -r ${BACKUP_DIR}/* ${DST_DIR}/"
    fi
done

集群一键启动/停止脚本

复制代码
#!/bin/bash
# 集群一键运维脚本:启动/停止Hadoop+Spark+HBase
# 用法:./cluster_start_stop.sh [start|stop]

# 全局配置
HADOOP_HOME="/opt/hadoop-3.3.4"
SPARK_HOME="/opt/spark-3.3.0"
HBASE_HOME="/opt/hbase-2.5.3"
SLAVE_NODES=("slave1" "slave2" "slave3")
OPS_LOG_DIR="/bigdata/ops/logs"
mkdir -p "${OPS_LOG_DIR}"
LOG_FILE="${OPS_LOG_DIR}/cluster_start_stop_$(date +%Y%m%d).log"
exec > "${LOG_FILE}" 2>&1

# 颜色输出函数
echo_info() { echo -e "\033[32m[INFO] $(date +'%Y-%m-%d %H:%M:%S') $1\033[0m"; }
echo_error() { echo -e "\033[31m[ERROR] $(date +'%Y-%m-%d %H:%M:%S') $1\033[0m"; }

# 集群启动函数
start_cluster() {
    echo_info "===== 开始启动大数据集群 ====="
    
    # 1. 启动Hadoop(HDFS+YARN)
    echo_info "步骤1:启动Hadoop集群..."
    ${HADOOP_HOME}/sbin/start-dfs.sh
    if [ $? -ne 0 ]; then
        echo_error "HDFS启动失败,查看日志:${LOG_FILE}"
        exit 1
    fi
    sleep 10  # 等待HDFS初始化完成
    ${HADOOP_HOME}/sbin/start-yarn.sh
    if [ $? -ne 0 ]; then
        echo_error "YARN启动失败,查看日志:${LOG_FILE}"
        exit 1
    fi
    # 启动HistoryServer(便于查看任务历史)
    ${HADOOP_HOME}/sbin/mr-jobhistory-daemon.sh start historyserver

    # 2. 启动Spark集群
    echo_info "步骤2:启动Spark集群..."
    ${SPARK_HOME}/sbin/start-all.sh
    if [ $? -ne 0 ]; then
        echo_error "Spark启动失败,查看日志:${LOG_FILE}"
        exit 1
    fi
    # 启动Spark HistoryServer
    ${SPARK_HOME}/sbin/start-history-server.sh

    # 3. 启动HBase集群
    echo_info "步骤3:启动HBase集群..."
    ${HBASE_HOME}/bin/start-hbase.sh
    if [ $? -ne 0 ]; then
        echo_error "HBase启动失败,查看日志:${LOG_FILE}"
        exit 1
    fi

    # 4. 验证启动状态
    echo_info "===== 集群启动完成,验证核心进程 ====="
    jps | grep -E "NameNode|ResourceManager|Master|HMaster"
    for node in "${SLAVE_NODES[@]}"; do
        echo_info "节点${node}进程状态:"
        ssh root@${node} "jps | grep -E 'DataNode|NodeManager|Worker|RegionServer'"
    done
    echo_info "集群启动日志已保存至:${LOG_FILE}"
}

# 集群停止函数
stop_cluster() {
    echo_info "===== 开始停止大数据集群 ====="
    
    # 1. 停止HBase集群
    echo_info "步骤1:停止HBase集群..."
    ${HBASE_HOME}/bin/stop-hbase.sh

    # 2. 停止Spark集群
    echo_info "步骤2:停止Spark集群..."
    ${SPARK_HOME}/sbin/stop-history-server.sh
    ${SPARK_HOME}/sbin/stop-all.sh

    # 3. 停止Hadoop集群
    echo_info "步骤3:停止Hadoop集群..."
    ${HADOOP_HOME}/sbin/mr-jobhistory-daemon.sh stop historyserver
    ${HADOOP_HOME}/sbin/stop-yarn.sh
    ${HADOOP_HOME}/sbin/stop-dfs.sh

    # 4. 验证停止状态
    echo_info "===== 集群停止完成,验证进程是否清理 ====="
    jps | grep -vE "Jps|${0##*/}"
    for node in "${SLAVE_NODES[@]}"; do
        echo_info "节点${node}剩余进程:"
        ssh root@${node} "jps | grep -vE 'Jps'"
    done
    echo_info "集群停止日志已保存至:${LOG_FILE}"
}

# 主逻辑
if [ $# -ne 1 ]; then
    echo "用法:$0 [start|stop]"
    exit 1
fi

case $1 in
    "start") start_cluster ;;
    "stop") stop_cluster ;;
    *) echo_error "无效参数,仅支持start/stop"; exit 1 ;;
esac

exit 0
相关推荐
BD_Marathon2 小时前
Vue3_事件渲染命令
开发语言·javascript·ecmascript
倔强的小石头_2 小时前
Python 从入门到实战(十一):数据可视化(用图表让数据 “说话”)
开发语言·python·信息可视化
StudyWinter2 小时前
【c++】thread总结
开发语言·c++·算法
小鸡脚来咯2 小时前
java泛型详解
java·开发语言
liuyouzhang2 小时前
备忘-国密解密算法
java·开发语言
北冥有一鲲2 小时前
LangChain.js:Tool、Memory 与 Agent 的深度解析与实战
开发语言·javascript·langchain
吴佳浩 Alben2 小时前
Python入门指南(六) - 搭建你的第一个YOLO检测API
开发语言·python·yolo
love530love2 小时前
Win11+RTX3090 亲测 · ComfyUI Hunyuan3D 全程实录 ③:diso 源码编译实战(CUDA 13.1 零降级)
开发语言·人工智能·windows·python·comfyui·hunyuan3d·diso
qq_377112372 小时前
JAVA的平凡之路——此峰乃是最高峰JVM-GC垃圾回收器(2)-06
java·开发语言·jvm