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
-
1\$\begingroup\$ The backslashes before newlines inside $PERLCMD are not needed. \$\endgroup\$choroba– choroba2023年08月29日 21:54:05 +00:00Commented Aug 29, 2023 at 21:54
-
4\$\begingroup\$ There is a point when leaving bash and switching completely to perl makes sense. \$\endgroup\$mpapec– mpapec2023年08月30日 06:23:08 +00:00Commented Aug 30, 2023 at 6:23
1 Answer 1
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.