5
\$\begingroup\$

The following function searches for disks whose partitions all have an attribute that match a filter when listed with lsblk. Comments are in TomDoc format.

# Public: finds drives in /dev/sd* whose partitions all have an attribute that matches a filter.
# 
# 1ドル - filter (default: '.*')
# 2ドル - attribute (default: 'MOUNTPOINT')
#
# Returns full paths to disks whose attributes match the filter
#
# Examples
# lsblk /dev/sda -oTYPE,PATH,MOUNTPOINTS --pairs
# # TYPE="disk" PATH="/dev/sda" MOUNTPOINTS=""
# # TYPE="part" PATH="/dev/sda1" MOUNTPOINTS="/boot/efi"
# # TYPE="part" PATH="/dev/sda2" MOUNTPOINTS="/var/snap/firefox/common/host-hunspell\x0a/"
# lsblk_disk_filter '(/var/snap/firefox/common/host-hunspell\\x0a/|/boot/efi)' 'MOUNTPOINTS'
# # /dev/sda
#
# lsblk /dev/sda -oTYPE,PATH,FSTYPE --pairs
# # TYPE="disk" PATH="/dev/sda" FSTYPE=""
# # TYPE="part" PATH="/dev/sda1" FSTYPE="vfat"
# # TYPE="part" PATH="/dev/sda2" FSTYPE="ext4"
# lsblk_disk_filter '(ext4|xfs|vfat)' 'FSTYPE'
# # /dev/sda
# 
# REQUIRES lsblk >= 2.33 for PATH output option - https://github.com/util-linux/util-linux/blob/master/Documentation/releases/v2.33-ReleaseNotes#L372
# TODO: add support for /dev/nvme* (I don't have hardware to test this...)
lsblk_disk_filter () {
 local filter="${1:-'.*'}";
 local attribute="${2:-'MOUNTPOINT'}"
 local PERLCMD='my ($type, $path, $attr) = /^TYPE\="([^"]*)"\s*PATH\="([^"]*)"\s*$col\="([^"]*)"\s*$/ or next; # VAR ASSIGNMENT \
 if( $type=~/disk/i){ # CHECK IF TYPE IS DISK \
 printf("%s ",$disk); # PRINTING LAST DISK \
 $disk=$path; # ASSIGN NEXT DISK \
 } elsif($attr!~/$filter/){ # PARTITION ATTRIBUTE MISMATCH TEST \
 $disk=""; # DELETING DISK ON MISMATCH \
 } END{ printf($disk); } # PRINT LAST DISK'
 lsblk --pairs --noheadings --ascii -o TYPE,PATH,$attribute /dev/sd* | perl -s -wnl -E "${PERLCMD}" -- -filter="$filter" -disk='' -col=$attribute
 # perl switch example: https://stackoverflow.com/questions/31155659/how-do-i-pass-command-line-options-to-a-perl-program-with-perl-e
 # /dev/sdx describes SCSI/SATA devices, /dev/sdx\d+ describes their partitions.
 # See the /dev/ naming convention described in the "devices" section in fdisk.
} # END lsblk_disk_filter
Sᴀᴍ Onᴇᴌᴀ
29.5k16 gold badges45 silver badges202 bronze badges
asked Aug 29, 2023 at 20:45
\$\endgroup\$
2
  • 1
    \$\begingroup\$ The backslashes before newlines inside $PERLCMD are not needed. \$\endgroup\$ Commented Aug 29, 2023 at 21:54
  • 4
    \$\begingroup\$ There is a point when leaving bash and switching completely to perl makes sense. \$\endgroup\$ Commented Aug 30, 2023 at 6:23

1 Answer 1

5
\$\begingroup\$

Given that the majority of this is Perl, it's probably worth using Perl as the main interpreter and using that to invoke lsblk directly.

Alternatively, use shell more, and consider using JSON output and jq for the parsing. That might fix the bug that we don't correctly parse anything which lsblk prints using hex escapes.

We're not using a tree display from lsblk, so the --ascii option is redundant.


As a starting point for using jq, this simple program finds the disks:

lsblk --json --noheadings -O |
 jq '.blockdevices[]|select(.type=="disk")|.path'

It shouldn't be hard to extend this to add additional selectors to the select() call.

answered Aug 30, 2023 at 13:02
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.