How to check a disk for partitions for use in a script in Linux?
Asked Answered
M

4

9

I'm scripting something in Bash for Linux systems. How would I check a disk for partitions in a robust manner?

I could use grep, awk, or sed to parse the output from fdisk, sfdisk, etc., but this doesn't seem to be an exact science.

I could also check if there are partitions in /dev, but it is also possible that the partitions exist and haven't been probed yet (via partprobe, as an example).

What would you recommend?

Mcfall answered 11/11, 2014 at 19:51 Comment(4)
What are you trying to detect exactly? What is your ultimate goal?Snider
sfdisk -d produces a format that is somewhat easier to parse, although still not ideal. kpartx -l is even better in that regard, if you have it installed. There may be other utilities as well.Vinificator
@Ethan Reisner: No catch; I'm merely just checking for partitions. If there aren't any, the script will eventually make a new MBR partition schema and create one large partition on the drive.Mcfall
sfdisk on RHEL 5.5 complains about GPT label. Asks me to use parted instead.Sprinkler
M
13

I think I figured out a reliable way. I accidentally learned some more features of partprobe while reading the man page:

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

Used together, I can scan a disk for partitions without updating the kernel and get a reliable output to parse. It's still parsing text, but at least the output isn't as "human-oriented" as fdisk or sfdisk. This also is information as read from the disk and doesn't rely on the kernel being up-to-date on the partition status for this disk.

Take a look:

On a disk with no partition table:

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

On a disk with a partition table but no partitions:

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

On a disk with a partition table and one partition:

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

On a disk with a partition table and multiple partitions:

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

It is important to note that every exit status was 0 regardless of an existing partition table or partitions. In addition, I also noticed that the options cannot be grouped together (partprobe -d -s /dev/sdb works while partprobe -ds /dev/sdb does not).

Mcfall answered 11/11, 2014 at 20:52 Comment(1)
learned something new. And this might be a better way, as you say, to be machine parsed. Thanks.Sprinkler
S
0

Another option is to run:

lsblk

See https://unix.stackexchange.com/a/108951

Stinkstone answered 9/7, 2015 at 18:16 Comment(1)
lsblk does not exist on RHEL 5.5Sprinkler
F
0

you could also use:

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

if a partition (first partition) exist it return true and otherwise false

Fara answered 8/8, 2021 at 22:30 Comment(0)
W
0

lsblk

If you want partition information from lsblk:

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

If you want to know whether a top level block device is partitioned or not, you can check the partition type, and restrict the results to skip dependent devices. (e.g. show only /dev/sda, ignoring /dev/sda1, /dev/sda2, etc)

For example:

# 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

To determine if a disk has a partition table using 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

You could also try partx, which will return zero if a partition table exists, or non-zero if it does not. Note that it also returns non-zero for a whole bunch of other reasons (insufficient permission, non-existent device, etc), which complicates things if you want to know conclusively that a device is not partitioned:

# 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

NOTE: lsblk doesn't appear to provide filesystem or partition type information for WSL virtual filesystems. It outputs a blank line above, even when df -T shows a filesystem type.

If you need to see some information about WSL virtual disks, parted might help (note: sudo required):

# 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
Welterweight answered 25/10, 2023 at 1:6 Comment(2)
cloud-init does this by counting the number of partitions returned from lsblk. If you're just trying to safely initialise a disk for a VM, cloud-init's disk_setup flag overwrite: false might be all you need.Welterweight
If you're trying to do this for a data disk with Terraform, you might also run into an issue where cloud-init runs before the disk is attached. In this case, you'll need to tell cloud-init to wait for the disk.Welterweight

© 2022 - 2024 — McMap. All rights reserved.