lvm 扩容脚本
一、需求
1、对已经分区好的/backup进行卸载,把空间扩容到/healsci
2、对新磁盘sdb这种,加入逻辑卷,扩容空间到/healsci
3、可进行功能选择,要做哪一种扩容
二、代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | #!/bin/bash # set -e # Get partition mount paths and volume group name get_mount_points() { BACKUP_MOUNT_POINT = $(df - - output = target | grep / backup) HEALSCI_MOUNT_POINT = $(df - - output = target | grep / healsci) if [ - z "$HEALSCI_MOUNT_POINT" ]; then echo "/healsci partition is not mounted correctly, please check the system status." exit 1 fi VG_NAME = $(lvdisplay | grep 'VG Name' | head - n 1 | awk '{print $3}' ) BACKUP_LV_PATH = $(lvdisplay | grep 'LV Path' | grep "$VG_NAME/backup" | awk '{print $3}' ) HEALSCI_LV_PATH = $(lvdisplay | grep 'LV Path' | grep "$VG_NAME/healsci" | awk '{print $3}' ) echo '-------------------------------' echo "VG Name: $VG_NAME" echo "Backup LV Path: $BACKUP_LV_PATH" echo "Healsci LV Path: $HEALSCI_LV_PATH" echo - e '----------------------------\n' } # Function 1: Expand /backup to /healsci expand_backup() { # Check if rsync is installed if ! command - v rsync &> / dev / null; then echo "rsync is not installed, please install it before running this script." exit 1 fi if [ - z "$BACKUP_MOUNT_POINT" ]; then echo "/backup partition is not mounted, please check the system status." exit 1 fi # Get space before expansion in bytes BEFORE_SPACE = $(df - - output = size - B1 "$HEALSCI_MOUNT_POINT" | tail - n 1 | xargs) # Synchronize data rsync - avh - - progress / backup / "$HEALSCI_MOUNT_POINT/backup/" # Unmount /backup partition umount / backup || { echo "/backup is in use and cannot be unmounted." lsof + D / backup exit 1 } echo "Successfully unmounted /backup" # Remove the logical volume lvremove - f "$BACKUP_LV_PATH" # Extend the healsci volume group lvextend - l + 100 % FREE "$HEALSCI_LV_PATH" # Extend the filesystem FS_TYPE = $(df - T "$HEALSCI_LV_PATH" | awk 'NR==2 {print $2}' ) if [ "$FS_TYPE" = = "ext4" ]; then resize2fs "$HEALSCI_LV_PATH" elif [ "$FS_TYPE" = = "xfs" ]; then xfs_growfs "$HEALSCI_LV_PATH" else echo "Unsupported filesystem type: $FS_TYPE" exit 1 fi # Get space after expansion in bytes AFTER_SPACE = $(df - - output = size - B1 "$HEALSCI_MOUNT_POINT" | tail - n 1 | xargs) # Calculate expanded space in bytes EXPANDED_SPACE = $(($AFTER_SPACE - $BEFORE_SPACE)) # Display results in human-readable format echo "Space before expansion: $(numfmt --to=iec $BEFORE_SPACE)" echo "Space after expansion: $(numfmt --to=iec $AFTER_SPACE)" echo "Expanded by: $(numfmt --to=iec $EXPANDED_SPACE)" # Update /etc/fstab sed - i '/\/backup/d' / etc / fstab # Create a symbolic link rm - rf / backup ln - s / healsci / backup / backup echo "Function 1 completed: /backup has been successfully expanded to /healsci!" } # Function 2: Add a new disk to LVM add_new_disks() { while true; do # List all unformatted disks UNFORMATTED_DISKS = $(lsblk - dn - o NAME, TYPE | while read - r disk type ; do if [ "$type" = "disk" ] && [ "$disk" ! = "sr0" ]; then if [ - z "$(lsblk -no FSTYPE " / dev / $disk ")" ]; then echo "$disk" fi fi done) if [ - z "$UNFORMATTED_DISKS" ]; then echo "No unformatted disks available for use." exit 1 fi echo "Available disks:" for disk in $UNFORMATTED_DISKS; do echo "$disk" done read - p "Please select the disk to add to LVM (e.g., sdb or sdb,sdc): " SELECTED_DISKS # Convert comma or space separated input to space-separated array SELECTED_DISKS = $(echo "$SELECTED_DISKS" | tr ', ' ' ' ) SELECTED_DISK_ARRAY = ($SELECTED_DISKS) # Check if each selected disk is valid valid = true for SELECTED_DISK in "${SELECTED_DISK_ARRAY[@]}" ; do SELECTED_DISK = $(echo "$SELECTED_DISK" | xargs) # Check if the disk is in the unformatted disk list if ! echo "$UNFORMATTED_DISKS" | grep - qw "$SELECTED_DISK" ; then echo "The selected disk $SELECTED_DISK is not in the unformatted disk list, please re-enter." valid = false break fi done if ! $valid; then continue fi # Get space before expansion in bytes BEFORE_SPACE = $(df - - output = size - B1 "$HEALSCI_MOUNT_POINT" | tail - n 1 | xargs) # Process all valid disks for SELECTED_DISK in "${SELECTED_DISK_ARRAY[@]}" ; do echo "Adding disk /dev/$SELECTED_DISK to LVM" pvcreate "/dev/$SELECTED_DISK" vgextend "$VG_NAME" "/dev/$SELECTED_DISK" # Confirm the logical volume exists if ! lvdisplay "$HEALSCI_LV_PATH" &> / dev / null; then echo "Logical volume does not exist, please check the settings." exit 1 fi lvextend - l + 100 % FREE "$HEALSCI_LV_PATH" # Extend the filesystem FS_TYPE = $(df - T "$HEALSCI_LV_PATH" | awk 'NR==2 {print $2}' ) if [ "$FS_TYPE" = = "ext4" ]; then resize2fs "$HEALSCI_LV_PATH" || { echo "Failed to extend the filesystem" ; exit 1 ; } elif [ "$FS_TYPE" = = "xfs" ]; then xfs_growfs "$HEALSCI_LV_PATH" || { echo "Failed to extend the filesystem" ; exit 1 ; } else echo "Unsupported filesystem type: $FS_TYPE" exit 1 fi # Get space after expansion in bytes AFTER_SPACE = $(df - - output = size - B1 "$HEALSCI_MOUNT_POINT" | tail - n 1 | xargs) # Calculate expanded space in bytes EXPANDED_SPACE = $(($AFTER_SPACE - $BEFORE_SPACE)) # Display results in human-readable format echo "Space before expansion: $(numfmt --to=iec $BEFORE_SPACE)" echo "Space after expansion: $(numfmt --to=iec $AFTER_SPACE)" echo "Expanded by: $(numfmt --to=iec $EXPANDED_SPACE)" echo "Disk /dev/$SELECTED_DISK has been successfully added to LVM!" done echo "Function 2 completed: Selected disks have been successfully added to LVM!" break done } # Main Program get_mount_points echo "Please select a number to perform the corresponding function:" echo "1) Expand /backup to /healsci" echo "2) Add new disks to LVM" echo "3) Execute all the above functions" echo read - p "Please enter your choice [1/2/3]: " CHOICE case $CHOICE in 1 ) expand_backup ;; 2 ) add_new_disks ;; 3 ) expand_backup add_new_disks ;; * ) echo "Invalid option, please enter 1, 2, or 3." exit 1 ;; esac echo "All operations completed!" |
三、重点逻辑
1、未格式化分区磁盘的判断
1 2 3 4 5 6 7 | UNFORMATTED_DISKS = $(lsblk - dn - o NAME, TYPE | while read - r disk type ; do if [ "$type" = "disk" ] && [ "$disk" ! = "sr0" ]; then if [ - z "$(lsblk -no FSTYPE " / dev / $disk ")" ]; then echo "$disk" fi fi done) |
拆解与解释
**UNFORMATTED_DISKS=$(...)
**:
这是一个命令替换的结构,将命令的输出结果存储在变量 UNFORMATTED_DISKS
中。
**lsblk -dn -o NAME,TYPE
**:
lsblk
是一个列出磁盘和块设备的命令
-d
选项表示只显示磁盘,不显示分区
-n
选项表示不打印标题行
-o NAME,TYPE
选项指定输出显示列,具体是设备名称 (NAME
) 和设备类型 (TYPE
)
输出类似于
1 2 3 | sda disk sdb disk sr0 rom |
**| while read -r disk type; do ... done
**:
管道符 (|
) 将 lsblk
的输出传递给 while
循环。循环会逐行读取上面的输出,将每行的设备名称赋值给变量 disk
,将设备类型赋值给变量 type
。
**if [ "$type" = "disk" ] && [ "$disk" != "sr0" ]; then
**:
该条件判断当前读取的设备类型是否为 "disk"
,并且设备名称不是 "sr0"
(通常是光驱设备)。
如果条件满足,代码块会执行下面的内容。
**if [ -z "$(lsblk -no FSTYPE "/dev/$disk")" ]; then
**:
lsblk -no FSTYPE "/dev/$disk"
命令用于检查当前设备的文件系统类型 (FSTYPE
)。
-n
选项表示不输出标题。
-o FSTYPE
指定只输出文件系统类型。
-z
检查命令的输出是否为空;即,无文件系统格式则返回 true
。
如果该设备没有文件系统,代码块会执行下面的内容。
**echo "$disk"
**:
如果前面的条件(设备是磁盘且没有文件系统)满足,则输出该设备名称 ($disk
)。
2、扩容空间的计算
1 2 3 4 5 6 7 | BEFORE_SPACE = $(df - - output = size - B1 "$HEALSCI_MOUNT_POINT" | tail - n 1 | xargs) AFTER_SPACE = $(df - - output = size - B1 "$HEALSCI_MOUNT_POINT" | tail - n 1 | xargs) EXPANDED_SPACE = $(($AFTER_SPACE - $BEFORE_SPACE)) echo "Space before expansion: $(numfmt --to=iec $BEFORE_SPACE)" echo "Space after expansion: $(numfmt --to=iec $AFTER_SPACE)" echo "Expanded by: $(numfmt --to=iec $EXPANDED_SPACE)" |
补充
2.1 numfmt
是一个命令行工具,用于在不同的数字格式之间进行转换。它在处理数值的表示和转换时非常有用,尤其是在需要人类可读的格式与用于计算的纯数字格式之间进行转换时。
--to=iec
选项是 numfmt
的一个参数,用于将数字转换为人类可读的格式,并使用 IEC(International Electrotechnical Commission)单位前缀。这种格式主要用于表示数据存储的尺寸和处理速度等,单位包括:
KiB
(kibibyte)= 1024 字节MiB
(mebibyte)= 1024 KibibytesGiB
(gibibyte)= 1024 MebibytesTiB
(tebibyte)= 1024 Gibibytes
1 2 | # numfmt --to=iec 4852936458240 4.5T |
2.2 df --output=size -B1
在 df
命令中,--output=size
和 -B1
选项结合使用,用于指定输出格式和块大小:
-
--output=size
: 这个选项指定要输出的列为“size”,即文件系统的总大小。这是df
的自定义输出功能之一,允许用户选择只显示某些感兴趣的数据列。 -
-B1
: 这个选项将块大小设置为字节,df
默认显示的单位是以 1K(kilobyte)为计量单位
1 2 3 4 | df - - output - - help FIELD_LIST is a comma - separated list of columns to be included. Valid field names are: 'source' , 'fstype' , 'itotal' , 'iused' , 'iavail' , 'ipcent' , 'size' , 'used' , 'avail' , 'pcent' , 'file' and 'target' (see info page). |
3、打印文件系统的类型
1 | df - T / healsci | awk 'NR==2 {print $2}' |
-T 参数输出文件系统类型
NR是行,NF是列
NR==2 {print $2} 打印第二行第二列