插曲:grep提取字符串里的数字(非常有用)
预期该指令可以提取字符串里的数字:echo a11b222c3333d44444|grep -o "[0-9]*"
但是因为*表示前面的iteam匹配0次或多次,匹配0次就是空,而空是任何字符串的子集。
用 grep -o "[0-9]\+" 可以准确提取字符串,或者 grep -o "[0-9]*[0-9]"
我自己写的脚本如下,存在一定的不完善,稍后讲解。
#dynamiclly resize virtual machine's img's disk
#!/bin/bash
# input args : path of VR template img, ( *.img )
# path of target VR (*.qcow2)
# target size of VR ( %d )
# note, minimum size of VR is 2G , if smaller than , exit directly
#set x;
TEMPLATE=$1 #虚拟机模版路径
TARGET=$2 #新生成的虚拟机镜像路径
SIZE=$3 #目标磁盘空间大小
PER_KB=1024 #二进制转换的单位:1024
#提取虚拟机镜像第2块磁盘容量
IMG_INFO=`qemu-img info $TEMPLATE | grep "virtual size" | awk '{print $4}' | grep -o "[0-9]\+"`
#计算磁盘的大小,以GB为单位
ORIGIN_SIZE=$[IMG_INFO / PER_KB / PER_KB / PER_KB]
if [ "$SIZE" -le "$ORIGIN_SIZE" ] #默认是2G,如目标磁盘空间小于等于2G,直接返回,无操作
then
echo "target size no bigger than minimum size[2 G], do nothing"
exit 0
fi
add=`expr "$SIZE" - "$ORIGIN_SIZE"`
echo "$add G will be added.."
#before getting partition table , it's essential to convert *.img or *.qcow2 to *.raw .
TEMP=temp.raw
echo "temp name is $TEMP"
qemu-img convert -O raw $TEMPLATE $TEMP #虚拟机镜像格式转换,在动态扩容之前,需要转换格式
if [ -f "$TEMP" ]
then
echo "$TEMP has been converted !"
else
echo fail to convert $TEMPLATE
exit 0
fi
echo begin to resize
size=+"$add"G
echo begin to $size
qemu-img resize $TEMP $size
PER_SECTOR=512
START_SEC=`parted temp.raw unit s print | tail -n 2 | awk '{print $2}'`
oldSector=$(parted $TEMP unit s print | tail -n 2 | head -n1 | awk '{print $3}')
echo "original oldSector size : "$oldSector""
oldSecDig=${oldSector%*s}
newSector=$[add * PER_KB * PER_KB * PER_KB / PER_SECTOR]
tarSector=$[newSector + oldSecDig]
echo target Sector : $tarSector
echo "start to delete second partition.."
lastPartition=`parted $TEMP unit s print | tail -n 2 | awk '{print $1}'`
parted $TEMP unit s rm $lastPartition
echo "finish deleting second partition, start to resize partition"
echo "start : $START_SEC, end : $tarSector"
parted $TEMP unit s mkpart primary $START_SEC ${tarSector}s
echo "write back new sector size finished !"
loopdev=`losetup -f` #采用系统环回设备挂载镜像,其特点是可以在挂载的时候指定偏移地址,即只挂载镜像的第二块磁盘
echo "available loop dev : $loopdev"
losetup $loopdev -o $[${START_SEC%*s} * PER_SECTOR] $TEMP
e2fsck -f $loopdev #采用系统命令,让新的磁盘可用
resize2fs -d 2 $loopdev
e2fsck -f $loopdev
sync
losetup -d $loopdev
echo convert $TEMP to $TARGET
qemu-img convert -O qcow2 $TEMP $TARGET
echo deleting $TEMP
#rm -rf $temp
老大帮忙修改后的脚本如下,考虑了更多的细节和出错处理
#!/bin/bash
# input args : path of VR template img, ( *.img )
# path of target VR (*.qcow2)
# target size of VR ( %d )
# note, minimum size of VR is 2G , if smaller than , exit directly
set -e;
function usage() {
echo "$0 <temp> <target> <size>"
}
function cleanup() {
if [ -n "$TEMP_DISKIMG" -a "$keep_TEMP" = n ]
then
echo "delete $TEMP_DISKIMG"
rm -f $TEMP_DISKIMG
fi
if [ -n "$loopdev" ]
then
echo "unmap $loopdev"
losetup -d $loopdev
fi
}
function cleanup_signal() {
echo "cleanup on got signal"
cleanup
}
function cleanup_exit() {
echo "cleanup on exit"
cleanup
}
if [ $# -lt 3 ]
then
usage
exit 1
fi
if [ ! -f $TEMPLATE ]; then
echo "$TEMPLATE not exists"
exit 1
fi
TEMPLATE=$1
TARGET=$2
SIZE=$3
# internal
TEMP_DISKIMG=
loopdev=
# config
keep_TEMP=n
logfile=
#/tmp/ResizeImg.log
trap cleanup_signal QUIT
trap cleanup_signal INT
trap cleanup_exit EXIT
if [ -n "$logfile" ]
then
exec >>$logfile 2>&1
fi
PER_SECTOR=512
PER_KB=1024
template_disksize=`qemu-img info $TEMPLATE | grep "^virtual size" | awk '{print $4}' | grep -o "[0-9]\+"`
template_disksize_gb=$[template_disksize / PER_KB / PER_KB / PER_KB]
if [ "$SIZE" -lt "$template_disksize_gb" ]
then
echo "target size no bigger than minimum size[$template_disksize_gb G], do nothing"
exit 1
fi
if [ "$SIZE" -eq "$template_disksize_gb" ]
then
cp $TEMPLATE $TARGET
exit 0
fi
#before getting partition table , it's essential to convert *.img or *.qcow2 to *.raw .
TEMP_DISKIMG=$(mktemp --tmpdir ResizeImg-XXXXXX.raw) #创建格式转换后的镜像名称,名称随机且保证唯一
echo "temp disk file is $TEMP_DISKIMG"
qemu-img convert -O raw $TEMPLATE $TEMP_DISKIMG
add=$[SIZE - template_disksize_gb]
echo begin to resize +${add}G
qemu-img resize $TEMP_DISKIMG +${add}G
lastPartition=$(parted $TEMP_DISKIMG unit s print | tail -n 2 | awk '{print $1}')
startSector=$(parted $TEMP_DISKIMG unit s print | tail -n 2 | awk '{print $2}')
startSector=${startSector%*s}
endSector=$(parted $TEMP_DISKIMG unit s print | tail -n 2 | head -n1 | awk '{print $3}')
endSector=${endSector%*s}
newEndSector=$[endSector + add * PER_KB * PER_KB * PER_KB / PER_SECTOR]
echo "Action: add ${add}G bytes to last partition $lastPartition"
echo " Old: partition ${lastPartition} sectors [${startSector}s, ${endSector}s)"
echo " New: partition ${lastPartition} sectors [${startSector}s, ${newEndSector}s)"
echo "start to delete second partition.."
parted $TEMP_DISKIMG unit s rm $lastPartition
echo "start to resize partition"
parted $TEMP_DISKIMG unit s mkpart primary ${startSector}s ${newEndSector}s
echo "Resize filesystems on parition $lastPartition"
loopdev=`losetup -f`
echo "map raw disk image $TEMP+${startSector}s to loop device $loopdev"
losetup $loopdev -o $[startSector * PER_SECTOR] $TEMP_DISKIMG
echo "check file system consistency on $loopdev"
set +e # disable exit on error, since fsck will return error if file system corrected
e2fsck -y -f $loopdev
if [ $? -ge 4 ]; then
exit $?
fi
set -e # re-enable exit on error
echo "resize file system on $loopdev"
resize2fs -d 2 $loopdev
echo "re-check file system consistency on $loopdev"
set +e # disable exit on error
e2fsck -y -f $loopdev
if [ $? -ge 4 ]; then
exit $?
fi
set -e # re-enable exit on error
echo "sync cache"
sync
echo convert $TEMP_DISKIMG to $TARGET
qemu-img convert -O qcow2 $TEMP_DISKIMG $TARGET