免交互格式化并挂载新磁盘的 Shell 脚本

业务系统一般单独挂一块数据盘存数据。拿到新盘后要格式化、分区、挂载、写 fstab,一两台机器手工做还行,节点一多就该交给脚本。下面这份脚本面向 CentOS,用 expect 做到全程免交互。

脚本的执行逻辑

流程分四段:先检查 expect 是否已装,没装就 yum 装上,并对 /etc/fstab 执行 chattr -i 解锁;然后用 lsblk 找尚未分区挂载的新盘(按 /sd 前缀匹配,awk 统计只出现一次的盘名);接着用 expect -c 驱动 fdisk,依次应答新建主分区、默认分区号、默认起始扇区、整个磁盘、wq 写入;最后 mkfs.xfs 格式化分区、写入 fstab、挂载到 /data,并重新 chattr +i 锁住 fstab。分区和格式化的交互提示词依赖系统语言,所以脚本按 LANG 分了 zh_CN 和 en_US 两个分支。

完整脚本

#!/usr/bin/env bash
#===============================================================================
#
#          FILE: Disk_Initialize.sh
# 
#         USAGE: ./Disk_Initialize.sh 
# 
#   DESCRIPTION: Linux CentOS Disk免交互格式化分区、挂载
# 
#  ORGANIZATION: DingQz dqzboy.com
#       CREATED: 2021
#===============================================================================

# 安装软件
EXPECT=`yum list installed | grep -w expect`
if [ $? -eq 0 ];then
   echo
   echo
   echo "--------------------------------------------------------------------------"
   echo "               Yum Install expect Skip..."
   echo "--------------------------------------------------------------------------"
   echo
   echo
else 
   yum -y install expect
   echo
   echo
   echo "--------------------------------------------------------------------------"
   echo "               Yum Install expect Done..."
   echo "--------------------------------------------------------------------------"
   echo
   echo
fi

# 解锁文件
chattr -i /etc/fstab

OS_CN() {
# 注意修改磁盘名称前缀,例如这里的 /sd
Dsk=`lsblk -r --output NAME,MOUNTPOINT | awk -F / '/sd/ { dsk=substr($1,1,3);dsks[dsk]+=1 } END { for ( i in dsks ) { if (dsks[i]==1) print i } }'`
Disk="/dev/${Dsk}"
DiskP="${Disk}1"
if [ ! -z "${Dsk}" ];then
expect -c "
  spawn fdisk ${Disk}
  expect {
    -re "(.*)三思(.*)(n*)(.*)获取帮助(.*)" { send "nr";exp_continue }
    "default p" { send "r";exp_continue }
    "分区号" { send "r";exp_continue }
    "起始 扇区" { send "r";exp_continue }
    "Last 扇区" { send "r";exp_continue }
    "命令" { send "wqr";exp_continue }
  }
"
else
   echo
   echo
   echo "--------------------------------------------------------------------------"
   echo "               The new disk was not found. Exit..."
   echo "--------------------------------------------------------------------------"
   echo
   exit 1
fi
}

OS_EN() {
Dsk=`lsblk -r --output NAME,MOUNTPOINT | awk -F / '/sd/ { dsk=substr($1,1,3);dsks[dsk]+=1 } END { for ( i in dsks ) { if (dsks[i]==1) print i } }'`
Disk="/dev/${Dsk}"
DiskP="${Disk}1"
if [ ! -z "${Dsk}" ];then
expect -c "
  spawn fdisk ${Disk}
  expect {
    -re "(.*)careful(.*)(n*)(.*)help(.*)" { send "nr";exp_continue }
    "default p" { send "r";exp_continue }
    "Partition number" { send "r";exp_continue }
    "First sector" { send "r";exp_continue }
    "Last sector" {send "r";exp_continue }
    "Command" { send "wqr";exp_continue }
  }
"
else
   echo
   echo
   echo "--------------------------------------------------------------------------"
   echo "              The new disk was not found. Exit..."
   echo "--------------------------------------------------------------------------"
   echo
   exit 1
fi
}

Mkfs_Disk() {
sleep 3

# 格式化分区
Partitions=`blkid | awk -F ":" '{print $1}'| grep "${DiskP}"`
if [ $? -eq 0 ];then
   echo
   echo
   echo "--------------------------------------------------------------------------"
   echo "               Formatted Done"
   echo "--------------------------------------------------------------------------"
   echo
   echo
else
   mkfs.xfs -f -n ftype=1 ${DiskP}
fi

if ! grep "${DiskP}" /etc/fstab; then
cat >> /etc/fstab <<EOF
${DiskP} /data                   xfs     defaults        1 0
EOF
echo "--------------------------------------------------------------------------"
fi

# 创建挂载目录
mkdir -p /data
mount ${DiskP}  /data

# 非ROOT用户不允许编辑以下文件
chattr +i /etc/fstab
}

# 判断系统语言
OS_LANG=`echo $LANG | awk -F "." '{print $1}'`
if [ "${OS_LANG}" == "en_US" ];then
   OS_EN
   Mkfs_Disk
elif [ "${OS_LANG}" == "zh_CN" ];then
   OS_CN
   Mkfs_Disk
else
   echo "Sorry script does not support this system."
fi 

expect 用到的几个指令

  • expect -c:在命令行上直接跟要执行的 expect 命令,命令要用引号包住,防止被 shell 拆散;
  • spawn:启动一个进入交互模式的程序,后面跟要驱动的命令;
  • expect:等待匹配输出,匹配成功就执行后面的动作;
  • send:发送指定字符串,r 相当于回车;
  • exp_continue:匹配成功后继续下一轮匹配,用来串起整个交互过程。

使用前确认几件事

脚本只挑选没有分区、没有挂载点的 sd 前缀磁盘,识别到多块新盘时只取一块;挂载点写死在 /data,改路径要同时动 fstab 追加和 mount 两处;磁盘前缀 /sd 之外(如 vdb、nvme)需要改匹配式;fstab 被加过 +i 之后,后续手工编辑要先 chattr -i,否则改不动。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容