Linux分区工具parted完全指南:GPT分区、在线扩容与自动化脚本实践
做服务器运维这些年,我几乎每天都要跟磁盘分区打交道。今天想认真聊一聊parted分区工具,这是GNU出品的一个命令行分区工具,也是我在处理GPT分区表、超大容量磁盘和自动化初始化任务时的首选。很多人一上来就习惯用fdisk,但碰到超过2TB的磁盘,或者需要在脚本里批量创建分区时,fdisk就显得力不从心。parted既能管MBR,也能管GPT,还提供了稳定的非交互模式,特别适合写进自动化流程。不管你是运维工程师、测试环境的搭建者,还是偶尔给自己电脑加一块硬盘的折腾党,这篇文章都能帮上忙。我会从工具选择、分区表原理、实操步骤到生产环境常见故障,把parted分区工具的完整用法整理一遍。
1. 为什么选择parted:三个关键场景和与fdisk的对比
1.1 我什么时候会优先用parted而不是fdisk
实际运维中,我优先选parted主要是在三类场景。
第一类是新服务器初始化数据盘。服务器上的数据盘往往不止一块,容量从1TB到几十TB都有可能。用parted一条命令建好GPT分区表,再一条命令创建分区,整个过程可以完全在无交互状态下完成,比手动敲fdisk里的菜单高效太多。
第二类是调整分区大小。parted的resizepart命令可以直接修改分区边界,配合resize2fs或xfs_growfs使用,通常不需要重启系统就能完成在线扩容。fdisk在这方面很弱,它只能删掉分区重建,操作风险完全不同量级。
第三类是写自动化脚本。parted的-s非交互模式支持一条命令直接完成mklabel、mkpart等操作,非常适合Shell脚本、Ansible等配置管理工具。fdisk和gdisk虽然也能用管道输入模拟非交互,但输出格式不稳定,出错排查成本很高。
再说一个很现实的原因:parted是几乎所有主流Linux发行版都自带或软件源里直接能装的工具,没有额外依赖。你不需要为一个分区操作去单独安装什么图形界面,它就是一个干干净净的命令行工具。
1.2 parted和fdisk、gdisk的定位差异
三个工具经常被拿来对比,但它们的定位是有明显区别的。
| 工具 | 分区表支持 | 脚本化能力 | 分区大小调整 | 适用场景 |
|---|---|---|---|---|
| fdisk | 主要面向MBR,新版可处理GPT | 一般,适合交互 | 不支持 | MBR分区的日常查看和修改 |
| gdisk | 面向GPT,可处理MBR | 较弱,重交互 | 不支持 | GPT分区表的修复和转换 |
| parted | MBR和GPT都支持 | 强,-s模式稳定 | 支持resizepart | 新盘初始化、批量分区、扩容 |
fdisk是MBR时代的经典工具,不少人习惯敲fdisk /dev/sdb再按n创建分区。但MBR对超过2TB的磁盘束手无策,而且主分区数量最多4个,碰到多分区场景会非常麻烦。新版fdisk虽然也支持GPT,但它的工作方式还是围绕交互菜单设计的。
gdisk则是GPT时代的专门工具,功能很强大,尤其是修复损坏的GPT分区表时很有用。但它的脚本化能力一般,如果你只是想快速建一个GPT分区并写入文件系统,用gdisk会感觉步骤冗余。
parted的价值正好在两者之间:既支持全部主流分区表,又能通过-s参数做到真正的静默批量执行。我对它的定位是“生产力工具”,而不是“维修工具”。
1.3 parted的能力边界
使用parted前要先明确它的能力范围:它做的是分区表层面的操作,不负责创建文件系统。命令包括mklabel、mkpart、rm、resizepart、set等,能创建和删除分区、设置分区类型标志、修改分区表标签类型。但你在parted里指定ext4、xfs这类参数时,它只是把这个类型写入分区表元数据,并不会真正格式化分区。格式化要另外执行mkfs.ext4或mkfs.xfs。
这个能力边界很重要。我有段时间看到新人用parted mkpart primary xfs 1MiB 100%,然后就以为分区已经是xfs文件系统了,直接挂载报错。parted只负责“画格子”,往格子里填什么内容,是mkfs的事。
另外parted对已挂载分区的操作是有限制的。你别指望在分区挂载状态下去删除它,内核会直接拒绝。这个限制不是parted的问题,而是Linux内核的保护机制,后面我会专门讲。
2. 分区前的核心原理:MBR、GPT、对齐与单位
2.1 MBR和GPT:为什么我们要了解分区表类型
要弄懂parted,得先弄懂分区表是什么。分区表就是记录磁盘上“哪里到哪里属于哪个分区”的地址索引。
MBR(Master Boot Record)是上世纪80年代的设计。它用32位逻辑块地址来描述分区边界,单块磁盘最大只能管理大约2TiB容量。在MBR下,一块磁盘最多只能有4个主分区。为了突破这个限制,后来引入了扩展分区和逻辑分区的概念,但实际使用中依然繁琐,而且逻辑分区的地址计算很容易出错。
GPT(GUID Partition Table)是UEFI时代的标准。它用64位逻辑块地址,单盘容量上限高到我们在现实里几乎碰不到边。它默认支持128个分区,每个分区都有独立的GUID和名称。更重要的一点是,GPT在磁盘头部和尾部各保存了一份分区表副本,一旦主分区表损坏,可以用备份分区表恢复。
我在给新数据盘做初始化时,只要磁盘容量超过2TB,或者预计以后可能扩容到2TB以上,一律选择GPT分区表。即便磁盘暂时小于2TB,我也更倾向GPT,因为这样以后扩容不用再折腾分区表转换。
parted里创建分区表的命令就一行:
parted -s /dev/sdb mklabel gpt如果是老式MBR,则是:
parted -s /dev/sdb mklabel msdos这里用的-s就是后面会反复提到的静默模式。
2.2 扇区大小与1MiB对齐的由来
“对齐”这个词,新手听上去很玄,其实原理不复杂。
传统磁盘的扇区是512字节,逻辑扇区也是512字节。但现代大容量硬盘物理扇区普遍是4096字节,这就是常说的4K扇区。有些硬盘为了让旧系统兼容,对外仍把逻辑扇区报成512字节,即512e模式。不管哪种情况,如果你创建分区时起始位置没有落在物理扇区的边界上,读写就可能出现跨扇区操作,导致性能下降,某些场景下甚至会明显拖慢IO。
Linux社区通用的安全对齐点是1MiB。1MiB等于1048576字节,正好是2048个512字节扇区的整数倍,也正好是256个4096字节扇区的整数倍。以1MiB作为分区起始位置,几乎能保证和所有常见存储设备的物理边界对齐,包括机械硬盘、SSD和云平台的虚拟磁盘。
parted在检测到分区起始位置没对齐时,会打印类似下面的警告:
Warning: The resulting partition is not properly aligned for best performance.看到这个警告,最省事的处理方式就是删掉分区重建,把起始位置从默认的0或某个非对齐位置改成1MiB。
2.3 parted的单位机制:MB、MiB和百分比的陷阱
parted里单位很灵活,但这也是最容易踩坑的地方。
进入parted交互模式后,print显示的分区大小默认使用MB,也就是十进制,1MB等于1000000字节。但你指定分区大小时,可以用MiB、GiB、TiB,这些是二进制单位,1MiB等于1048576字节。两者看起来差不多,在大容量磁盘上累加出来的误差很可观。所以我的习惯是:所有分区的start和end都用MiB或GiB指定,避免用MB。
parted还支持百分比,比如:
parted -s /dev/sdb mkpart data ext4 1MiB 100%这条命令的意思是新建分区,起始位置从1MiB开始,结束位置延伸到磁盘末尾。对一块全新数据盘来说,这个写法非常方便,直接占满剩余空间。但要注意,如果有多个分区,某个分区使用100%作为结束位置,它会一直延伸到磁盘末尾,很可能覆盖掉后面的分区。只有明确知道空间规划时,才建议用百分比。
我在命令里常写1MiB,但在print输出里看到的是1049kB,因为parted显示默认单位是MB。想看二进制单位,可以在交互模式里敲:
(parted) unit MiB也可以用命令行参数直接指定:
parted -s /dev/sdb unit MiB print搞清楚单位之间的换算,能帮你避免很多看似诡异的问题。
3. parted实操:初始化、分区、脚本化和扩容
3.1 动手前的检查与风险预案
先说一句话:parted没有退款功能,也不像rm那样有交互确认(早期版本还问几句,新版本在-s模式下是静默执行),命令敲下去,分区表就变了。所以动手前我有一套固定检查流程。
第一步,确认设备名。用lsblk或df -h看清楚目标磁盘对应的是哪个设备名。生产环境里误把sda当成sdb操作,搞挂系统盘的案例不止一次听过。
lsblk第二步,确认磁盘上没有正在使用的分区。可以看mount输出,也可以用df确认没有挂载点占用。
第三步,把当前分区表先记录一份:
parted -s /dev/sdb print有条件的可以截图或者存到日志里。万一操作到一半发现不对劲,这份记录能帮你判断原始的起点和终点。
第四步,确认磁盘里的数据不需要保留。凡是涉及分区表重写的操作,数据备份永远是第一优先级。parted的mklabel gpt会直接重建分区表,等于把磁盘上原有的分区记录清空。虽然数据块本身未必被覆盖,但分区记录没了之后,恢复成本非常高。无论什么时候,都别在真正重要的数据盘上尝试“先操作后恢复”。
3.2 全新数据盘初始化和分区的完整步骤
接下来演示一块全新的数据盘/dev/sdb从零开始初始化的过程。
先在多数Linux发行版上确认parted是否安装:
which parted如果没安装,CentOS/RHEL系列用yum,Debian/Ubuntu系列用apt:
yum install parted -y # 或者 apt install parted -y查看目标磁盘的基本信息:
lsblk /dev/sdb parted -s /dev/sdb print如果print给出“unrecognised disk label”之类的提示,说明这块盘还没有可识别的分区表。
创建GPT分区表:
parted -s /dev/sdb mklabel gpt再创建分区,起始位置1MiB,结束位置100%:
parted -s /dev/sdb mkpart data ext4 1MiB 100%这里的data是分区名称,在GPT里会很明确地显示出来。ext4只是写入分区表的文件系统类型标记,并不会真的格式化。如果你明确要用xfs,可以写xfs,也可以只写ext4再手动格式化,不影响最终结果。
创建完成后让内核重新读取分区表:
partprobe /dev/sdb有时候partprobe不会立即生效,可以补一条:
udevadm settle最后格式化和挂载:
mkfs.ext4 /dev/sdb1 mkdir -p /data mount /dev/sdb1 /data如果想要开机自动挂载,还要在/etc/fstab里写入UUID而不是设备名。因为设备名在重启后可能会变化,而UUID是唯一且稳定的。
查看UUID:
blkid /dev/sdb13.3 非交互模式:脚本化批量分区的固定套路
parted的-s参数是它最大的卖点。这个参数全称是--script,执行过程中不会等待任何交互输入,出现错误直接返回非零退出码。你可以放心地把parted -s写进Shell脚本循环里。
下面是我经常用来批量初始化多块数据盘的脚本范式:
#!/bin/bash set -e for disk in /dev/sdb /dev/sdc /dev/sdd; do echo "Processing $disk" parted -s "$disk" mklabel gpt parted -s "$disk" mkpart data ext4 1MiB 100% sleep 2 partprobe "$disk" mkfs.ext4 -F "${disk}1" done这里几个细节值得说明。
set -e让脚本在任意一条parted命令失败时直接退出,避免后续操作在错误状态下继续执行。sleep 2是给内核一点时间来创建对应的分区设备节点,部分虚拟化环境下分区设备节点创建有延迟,直接mkfs可能报“找不到设备”。mkfs.ext4 -F是强制格式化,因为磁盘上可能残留旧的元数据。
如果你不确定设备名,可以用/dev/disk/by-id/下面的路径来操作,这样不依赖/dev/sdX的枚举顺序。例如:
parted -s /dev/disk/by-id/wwn-0x5000c500a1b2c3d4 mklabel gpt然后用lsblk找到对应的分区设备节点进行格式化。
在脚本里解析parted输出时,可以加上unit MiB让输出更统一。比如要检查分区表类型,可以这样:
parted -s /dev/sdb print | grep -i "Partition Table"它会返回gpt或msdos,非常便于脚本判断。
3.4 在线扩容的完整流程:从resizepart到resize2fs
生产环境里经常遇到虚拟机磁盘扩容。比如虚拟机原来分配了50GB,后来空间不够,在虚拟化层把磁盘扩大到了100GB,但操作系统里的分区表还停留在50GB。这时候parted就是解决这个问题的核心工具。
先确认新的磁盘容量已经被系统识别:
parted -s /dev/sdb unit MiB print如果显示的还是旧容量,可能需要先在虚拟化层扫描设备,或者重启虚拟机。
接下来修改分区结束位置:
parted /dev/sdb resizepart 1 100%这条命令会把第1个分区的结束位置扩展到磁盘末尾。注意这里我没有加-s,因为parted在修改已存在分区时通常需要确认,交互模式下看得更清楚。部分版本也支持直接用-s,但交互输入一次确认会更稳妥。
执行后让内核重新读取分区表:
partprobe /dev/sdb到这里只是改了分区表,分区里的文件系统大小还停留在原来的50GB。接下来要根据文件系统类型选择扩展命令。
ext4文件系统使用resize2fs:
resize2fs /dev/sdb1xfs文件系统使用xfs_growfs,注意它的参数是挂载点,不是设备节点:
xfs_growfs /data这里还要提醒一点:如果分区处于挂载状态,resizepart虽然可以操作分区表,但内核可能迟迟不接受新分区信息。稳妥起见,扩容操作最好安排在业务低峰期,必要时先卸载分区再操作。对根分区扩容尤其要小心,卸载是不现实的,一旦内核重读分区表失败,只能重启。
parted有个历来的坑:resize命令和resizepart命令不是一回事。resize是老版parted里尝试调整分区和文件系统的命令,但对文件系统有严格限制;resizepart是新版本推荐的底层做法,它只修改分区表边界,不碰文件系统。所以我们的标准操作永远是:先resizepart改分区表,再用resize2fs或xfs_growfs扩展文件系统。顺序反了会出问题。
4. 生产环境避坑指南:常见报错与排查方法
4.1 分区表被占用:设备正忙到底怎么解决
这是parted操作里出现频率最高的一类报错,典型输出是:
Error: Partition(s) on /dev/sdb are being used.含义是内核还在使用目标分区。造成的原因大概率是分区已挂载,也可能被LVM卷组或swap分区占用。需要逐一排查。
用df -h查看挂载情况,用lsblk看分区是否被某个逻辑卷使用,用swapon --show看swap分区。
找到占用后,执行对应的释放操作:
umount /dev/sdb1 swapoff /dev/sdb1 vgchange -an <卷组名>有时候你用df看不到任何信息,但parted仍然报错,这时候可以排查是不是有进程在访问分区:
fuser -v /dev/sdb如果有进程占用,需要先停掉对应服务。实在找不到占用方,但又确认分区没有业务使用时,可以尝试:
sync然后重新执行parted操作。如果仍然不行,可能就需要停机重启,让内核完全释放对磁盘的引用。
4.2 GPT备份表损坏的修复方法
GPT分区表在磁盘头和尾各有一份。尾部备份表损坏并不影响系统正常识别分区,但parted会给出警告提示:
Warning: The backup GPT table is corrupt, but the primary appears OK.处理方式很简单。进入parted交互模式:
parted /dev/sdb执行print,parted会询问你是否修复。选择Fix即可。它会用主分区表重新生成损坏的备份表。
如果parted的交互修复没生效,或者想更深入地重建,可以交给gdisk。在gdisk里执行w写入,它会同时重建主分区表和备份分区表。gdisk是专门处理GPT的工具,在分区表损坏修复方面比parted更专业。
这里要区分情况:如果备份表损坏,问题不大,可以修复。如果主分区表也损坏,那就意味着分区信息可能丢失了一部分,得结合之前的print记录和实际数据来判断,不能盲目Fix。
4.3 分区重叠和空间不足的判断
创建分区时如果指定了错误的范围,可能遇到两类报错。
第一类是:
Error: Can't have overlapping partitions.说明你想要的分区结束位置已经超出了上一个分区的边界,分区之间互相重叠。处理方法是先用print查看现有分区的完整范围,然后重新规划新分区的start和end。
第二类是:
Error: Unable to satisfy all constraints on the partition.这种情况通常是指定的结束位置超过了磁盘实际容量,或者起始位置没有对齐导致parted无法满足条件。可以先用unit MiB print查看磁盘总大小,再重新确认start和end。
还有一种隐蔽情况:磁盘末尾剩余空间很小,你按百分比创建分区时,parted需要留出GPT备份表所需的空间,所以实际可创建的分区不会占满整个磁盘。如果看到“剩余空间不足”之类的报错,试试把end稍微调小一点。
4.4 脚本自动化中的几个经典翻车案例
这里把我在实际脚本中踩过的坑集中整理一下。
第一个坑:mkpart参数位置写错。parted的mkpart命令有几种合法写法。在GPT下建议不要写primary这个冗余参数,直接写名称、文件系统类型、起始、结束:
parted -s /dev/sdb mkpart data ext4 1MiB 100%如果你写成了:
parted -s /dev/sdb mkpart primary ext4 1MiB 100%也能跑,因为parted把primary当作part-type,把ext4当作名称,结果分区名称会变成ext4而不是data。虽然不影响挂载,但后期排查时分区名称混乱会让人困惑。
第二个坑:格式化前内核没有识别新分区。脚本里创建完分区后立即执行mkfs,偶尔会报/dev/sdb1: No such file or directory。解决方式是在中间加partprobe和sleep 2,让内核和udev有时间刷新设备节点。
第三个坑:重复执行脚本导致分区重叠。如果磁盘上已经有分区,再执行一次mkpart data ext4 1MiB 100%,parted会拒绝并提示空间不足或分区冲突。因此脚本里最好先判断磁盘当前是否有分区,或者统一先mklabel gpt再创建。
第四个坑:对已有数据磁盘执行mklabel。我在前面强调过,mklabel会重建整个分区表,等于把原有分区记录全部清空。有些人在生产环境手快敲了这条命令,结果数据找不回来了。执行mklabel之前,一定要确认这块盘不需要保留数据,或者已经完整备份。
第五个坑:使用/dev/sdX设备名时,重启后盘符漂移。如果脚本里硬编码了/dev/sdb,在一台物理机上可能某次重启后变成/dev/sdc。一个稳妥的替代方案是使用/dev/disk/by-id/下的设备链接,或者通过lsblk的序列号信息动态匹配目标磁盘。
下面是parted常用命令速查表,方便参考。
| 命令 | 作用 |
|---|---|
parted -s /dev/sdb print | 查看分区表 |
parted -s /dev/sdb mklabel gpt | 创建GPT分区表 |
parted -s /dev/sdb mklabel msdos | 创建MBR分区表 |
parted -s /dev/sdb mkpart data ext4 1MiB 100% | 创建分区 |
parted -s /dev/sdb rm 1 | 删除第1个分区 |
parted /dev/sdb resizepart 1 100% | 调整第1个分区结束位置 |
parted -s /dev/sdb set 1 lvm on | 设置分区标志 |
parted -s /dev/sdb unit MiB print | 以MiB为单位查看分区表 |
5. 这些年我总结的几个实操习惯
parted用久了,我在生产环境里逐渐养成了几个固定习惯。未必写在官方文档里,但确实帮我躲过不少麻烦。
第一个习惯是执行任何写操作前,先跑一次不带参数的parted print。哪怕只是把结果扫一眼,让“设备名”“磁盘容量”“当前分区表类型”这三个信息在脑子里过一遍,再决定后面敲什么命令。很多误操作都是因为脑子里的认知和实际磁盘状态不一致造成的。
第二个习惯是每次只做一步,做完就print确认。比如新盘初始化,我先执行mklabel gpt,然后print看分区表类型对不对,再执行mkpart,再print看分区范围对不对。看起来多敲了几行命令,但比一次性写一条长命令然后再验证要安全得多。parted是直接写盘的工具,脚本可以背锅,但数据恢复没有后悔药。
第三个习惯是扩容时永远先确认文件系统类型,再选扩展命令。ext4是resize2fs,xfs是xfs_growfs,两者不能混用。我见过同事对着xfs分区执行resize2fs,直接报错还不肯换命令,最后花了更多时间排查。
第四个习惯是在脚本里把parted命令和mkfs命令严格分开。parted只负责分区表,mkfs才负责文件系统。依赖parted去“顺便”格式化,是误解了它的职责边界。只要这个边界清晰,脚本写起来逻辑就非常干净。
parted分区工具本身就是个直接、高效、有点“危险”的工具,正因为它操作简单,我们更要在动手前多一分谨慎。如果你刚接触它,建议先找一块空白磁盘或者测试用的数据盘完整跑一遍流程,感受一下不同参数对分区表的影响。等真正进入生产环境,这些经验就会变成你的操作直觉。