如何在Linux脚本中检查磁盘的分区情况?

9
我正在为Linux系统编写Bash脚本。 如何以健壮的方式检查磁盘的分区?
我可以使用grep、awk或sed来解析fdisk、sfdisk等工具的输出,但这似乎不是一门精确的科学。
我也可以检查/dev中是否有分区,但也有可能分区存在但尚未被探测到(例如通过partprobe)。
您会推荐什么方法?

2
你究竟想要检测什么?你的最终目标是什么? - Etan Reisner
2
sfdisk -d 生成的格式有点容易解析,但仍不理想。如果您已安装 kpartx -l,那么它在这方面甚至更好。可能还有其他实用程序。 - twalberg
@Ethan Reisner:没有什么陷阱;我只是在检查分区。如果没有分区,脚本最终将创建一个新的MBR分区模式,并在驱动器上创建一个大分区。 - Synthead
RHEL 5.5 上的 sfdisk 抱怨 GPT 标签。要求我改用 parted - Felipe Alvarez
4个回答

13

我想我找到了一种可靠的方法。在阅读手册时,我无意中学到了关于partprobe的更多特性:

-d     Don’t update the kernel.
-s     Show a summary of devices and their partitions.

使用这两个工具,我可以在不更新内核的情况下扫描磁盘分区,并得到可靠的输出进行解析。虽然仍然是解析文本,但至少输出不像fdisksfdisk那样“面向人类”。这也是从磁盘读取的信息,不依赖于内核对该磁盘分区状态的最新更新。

看一下:

在没有分区表的磁盘上:

# partprobe -d -s /dev/sdb
(no output)

在一个具有分区表但没有分区的磁盘上:

# partprobe -d -s /dev/sdb
/dev/sdb: msdos partitions

在一个带有分区表和单个分区的磁盘上:
# partprobe -d -s /dev/sdb
/dev/sdb: msdos partitions 1

在一个带有分区表和多个分区的磁盘上:

# partprobe -d -s /dev/sda
/dev/sda: msdos partitions 1 2 3 4 <5 6 7>

需要注意的是,无论分区表或分区是否存在,每个退出状态均为0。此外,我还注意到选项无法组合在一起(partprobe -d -s /dev/sdb有效,而partprobe -ds /dev/sdb无效)。


1
学到了新东西。正如你所说,这可能是更好的方式,以便被机器解析。谢谢。 - Felipe Alvarez

0

在 RHEL 5.5 上不存在 lsblk 命令。 - Felipe Alvarez

0

你也可以使用以下命令:

parted /dev/sda print 1 &> /dev/null echo $?

如果分区存在(第一个分区),则返回 true,否则返回 false。


0

lsblk

如果你想从lsblk获取分区信息:

lsblk -n -o NAME,TYPE,FSTYPE,PTTYPE

如果你想知道一个顶级块设备是否被分区,你可以检查分区类型,并限制结果以跳过依赖设备(例如,只显示/dev/sda,忽略/dev/sda1、/dev/sda2等)。
例如:
# this device has a partition table
$ lsblk -nd -o PTTYPE /dev/sda
gpt

# this device is unformatted, and does not have a partition table
$ lsblk -nd -o PTTYPE /dev/sdd

# ^ outputs blank line

# this device does not exist
$ lsblk -nd -o PTTYPE /dev/sdf
lsblk: /dev/sdf: not a block device
$ echo $?    # non-zero exit code
32

使用lsblk命令来确定磁盘是否有分区表。
$ cat test.sh
#!/bin/bash

partitioned() {
        local DISK="$1"
        # Define PARTITION_CHECK as local here so we can capture the exit code
        # from lsblk. If we try to do it all in one go we end up capturing the
        # exit code of setting the variable as local rather than the exit code
        # of lsblk:
        # https://unix.stackexchange.com/a/637060/
        # https://tldp.org/LDP/abs/html/localvar.html
        local PARTITION_CHECK
        if PARTITION_CHECK=$(lsblk -nd -o PTTYPE "$DISK" 2> /dev/null)
        then
                if [ -z "$PARTITION_CHECK" ]
                then
                        echo "${DISK}: Not partitioned"
                elif [ -n "$PARTITION_CHECK" ]
                then
                        echo "${DISK}: Partitioned"
                fi
        else
                echo "${DISK}: Could not determine partition status"
        fi
}

for DISK in /dev/sda /dev/sdc /dev/sdf test
do
        partitioned "$DISK"
        echo
done

$ ./test.sh
/dev/sda: Partitioned

/dev/sdc: Not partitioned

/dev/sdf: Could not determine partition status

test: Could not determine partition status

partx

你也可以尝试使用partx命令,如果存在分区表,它将返回零,如果不存在,则返回非零值。请注意,它还会因为一系列其他原因(权限不足、设备不存在等)返回非零值,这会使得判断设备是否未分区变得复杂:

# disk with partition table
$ sudo partx /dev/sda
NR  START      END  SECTORS  SIZE NAME UUID
 1 227328 62916574 62689247 29.9G      a123bcf4-5678-912d-d345-6b78f90g1234
$ echo $?
0

# unformatted disk
$ sudo partx /dev/sdd
partx: /dev/sdd: failed to read partition table
$ echo $?
1

# non-existent disk
$ sudo partx /dev/sdc
partx: stat of /dev/sdc failed: No such file or directory
$ echo $?
1

注意:`lsblk`似乎无法提供WSL虚拟文件系统的文件系统或分区类型信息。即使`df -T`显示了文件系统类型,它也会输出一个空行。
如果您需要查看关于WSL虚拟磁盘的一些信息,`parted`可能会有所帮助(注意:需要`sudo`权限)。
# WSL virtual disk
$ DEV=/dev/sda; sudo parted -ms "$DEV" print 2>/dev/null | grep "$DEV" | cut -d: -f 6
loop

# real gpt partitioned disk
$ DEV=/dev/sda; sudo parted -ms "$DEV" print 2>/dev/null | grep "$DEV" | cut -d: -f 6
gpt

# real unformatted disk
$ DEV=/dev/sdd; sudo parted -ms "$DEV" print 2>/dev/null | grep "$DEV" | cut -d: -f 6
unknown

# non-existent disk
$ DEV=/dev/sdc; sudo parted -ms "$DEV" print 2>/dev/null | grep "$DEV" | cut -d: -f 6
# no output

cloud-init通过计算从lsblk返回的分区数量来实现这一点。如果您只是想为虚拟机安全地初始化磁盘,cloud-init的disk_setup标志overwrite: false可能就是您所需的全部。 - undefined
如果你正在尝试使用Terraform为数据磁盘进行操作,你可能会遇到一个问题,即cloud-init在磁盘附加之前就已经运行。在这种情况下,你需要告诉cloud-init要等待磁盘 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接