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

18k views Asked by At

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?

4

There are 4 answers

1
Synthead On BEST ANSWER

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).

2
daviewales On

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
0
Hamid Reza Moradi On

you could also use:

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

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

1
user3751385 On

Another option is to run:

lsblk

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