3

I am trying to find a hard drives manufacture/model based on the UUID that I know of a hard drive in a command.

I tried using lsblk -o FSTYPE,MOUNTPOINT,UUID,MODEL,SIZE to list all the hard drives and then store them in an array to find the UUID and its model. However the mounted hard drive's UUID never contains the model information of the hard drive.

It only lists the model hdd on the root location of a hdd ie /sda.

I am writing a bash script that stores the UUID and the manufacture/model of the hdd as well as the file system type so I can then automatically mount the hdd's that have a valid file system type on a folder prefix of /someLocation/${model}-${UUID-first-4-char}

The below creates two arrays at the moment, one for uuid and one for the file type.

 #create array
    fsTypeArray=()
    uuidArray=()
    mapfile -t fsTypeArray < <(lsblk -o FSTYPE,MOUNTPOINT,UUID | awk 'NF==2 {print $1}')
    mapfile -t uuidArray < <(lsblk -o FSTYPE,MOUNTPOINT,UUID | awk 'NF==2 {print $2}')

And then here is the if statement that either mounts ext4 or ntfs

index=0
    for i in "${fsTypeArray[@]}"
    do
        if [ $i == ntfs ] 
        then
            echo "mountNtfsDrive"
            currentDate="date +%Y%m%d%H%M%S"
            mountNtfsDrive "${uuidArray[$index]}" `$currentDate`
        elif [ $i == ext4 ]
        then
            echo "mount ext4" 
            currentDate="date +%Y%m%d%H%M%S"
            mountExt4Drive "${uuidArray[$index]}" `$currentDate`
        fi
        echo index
        let "index++"
         sleep 1s

I want to replace and remove hat currentDate into basically ${MODEL/MAKE-UUID(first 4 characters)}.

The currentDate basically uses the current date and time as a folder name but I want it to consistently create/mount on the same folder that is unique to that hdd's UUID and hard drive make/model.

eg ; mount UUID=1234567 /media/ext/western-digital-1234

Below are the two functions that mount the hard drives:

# Mount a ext4 drive
function mountExt4Drive {
    uuid=$1
    location=$2
    mkdir -pv "/home/$location"
    sleep 3s
    echo "mounting ext4 hdd $uuid in $location"
    mount UUID=$uuid $location
}

Mount NTFS drive

function mountNtfsDrive { echo "mounting ntfs $1 in $2" mkdir -pv "/home/$2" sleep 3s mount -t ntfs-3g "UUID=$1" "/home/$2" }

edit: the suggested post does not meet my requirements as its not finding the hard drive based on UUID and it is to do with USB attached storage devices

Criggie
  • 681
Jono
  • 525
  • 1
  • I know that the title of the question I linked to above is a bit misleading ... but, what you want is in the second part of the accepted answer to that question :-) – Raffa Jul 11 '22 at 09:50
  • @Raffai looked at that answer and its confusing to understand and seems like a completely different approach to getting the manufactur name etc. – Jono Jul 11 '22 at 10:30
  • Why not just add labels to every partition and mount those? lsblk -o name,fstype,size,fsused,label,partlabel,mountpoint I have my data on different drives. Main drive is just data, copies are in m2_data (my m2 sata drive), data_nvme (my nmve drive), data256a (one of my flash drives). – oldfred Jul 11 '22 at 15:08
  • Can you give a short explanation of your end-goal here? Do you have a lot of drives with unknown models/filesystems? I'm not sure if automount or filesystem labels would match your needs (ie, "UUID=blah" lines in /etc/fstab) Trying to avoid a XY answer. – Criggie Jul 11 '22 at 21:52

2 Answers2

5

Background

What you, indeed, want is the VENDOR,MODEL output formatting options but, with a twist(see workaround section below):

 lsblk -o FSTYPE,UUID,VENDOR,MODEL

You might as well want to print a list and stop printing headings(for better output parsing) by adding the options -ln and exclude loop devices by adding the option -e 7 ... See cat /proc/devices under Block devices: for other device types you might want to exclude and separate them by commas like -e 7,11,....

See more options with lsblk -h:

$ lsblk -h

Usage: lsblk [options] [<device> ...]

List information about block devices.

Options: -D, --discard print discard capabilities -E, --dedup <column> de-duplicate output by <column> -I, --include <list> show only devices with specified major numbers -J, --json use JSON output format -O, --output-all output all columns -P, --pairs use key="value" output format -S, --scsi output info about SCSI devices -T, --tree[=<column>] use tree format output -a, --all print all devices -b, --bytes print SIZE in bytes rather than in human readable format -d, --nodeps don't print slaves or holders -e, --exclude <list> exclude devices by major number (default: RAM disks) -f, --fs output info about filesystems -i, --ascii use ascii characters only -l, --list use list format output -M, --merge group parents of sub-trees (usable for RAIDs, Multi-path) -m, --perms output info about permissions -n, --noheadings don't print headings -o, --output <list> output columns -p, --paths print complete device path -r, --raw use raw output format -s, --inverse inverse dependencies -t, --topology output info about topology -w, --width <num> specifies output width as number of characters -x, --sort <column> sort output by <column> -z, --zoned print zone model --sysroot <dir> use specified directory as system root

-h, --help display this help -V, --version display version

Available output columns: NAME device name KNAME internal kernel device name PATH path to the device node MAJ:MIN major:minor device number FSAVAIL filesystem size available FSSIZE filesystem size FSTYPE filesystem type FSUSED filesystem size used FSUSE% filesystem use percentage FSROOTS mounted filesystem roots FSVER filesystem version MOUNTPOINT where the device is mounted MOUNTPOINTS all locations where device is mounted LABEL filesystem LABEL UUID filesystem UUID PTUUID partition table identifier (usually UUID) PTTYPE partition table type PARTTYPE partition type code or UUID PARTTYPENAME partition type name PARTLABEL partition LABEL PARTUUID partition UUID PARTFLAGS partition flags RA read-ahead of the device RO read-only device RM removable device HOTPLUG removable or hotplug device (usb, pcmcia, ...) MODEL device identifier SERIAL disk serial number SIZE size of the device STATE state of the device OWNER user name GROUP group name MODE device node permissions ALIGNMENT alignment offset MIN-IO minimum I/O size OPT-IO optimal I/O size PHY-SEC physical sector size LOG-SEC logical sector size ROTA rotational device SCHED I/O scheduler name RQ-SIZE request queue size TYPE device type DISC-ALN discard alignment offset DISC-GRAN discard granularity DISC-MAX discard max bytes DISC-ZERO discard zeroes data WSAME write same max bytes WWN unique storage identifier RAND adds randomness PKNAME internal parent kernel device name HCTL Host:Channel:Target:Lun for SCSI TRAN device transport type SUBSYSTEMS de-duplicated chain of subsystems REV device revision VENDOR device vendor ZONED zone model DAX dax-capable device

For more details see lsblk(8).

Workaround

Notice that lsblk will list VENDOR and MODEL for disks(i.e. block devices) and not partitions ... but you can get around that by implementing something like this(just a template ... modify it to your needs):

#!/bin/bash

for f in $(/bin/lsblk -nlo TYPE,NAME | /bin/awk '/part/ {print $2}') # Get partitions only do f="/dev/$f" # Set full path to partition uuid=$(/bin/lsblk -nlo PARTUUID "$f") # Get partition UUID fstype=$(/bin/lsblk -nlo FSTYPE "$f") # Get partition file system type d=$(/bin/lsblk -nldo PKNAME "$f") # Get partition block device d="/dev/$d" # Set full path to block device vendor=$(/bin/lsblk -nlo VENDOR "$d") # Get vendor of the block device model=$(/bin/lsblk -nlo MODEL "$d") # Get model of the block device echo "$f: PARTUUID=$uuid FSTYPE=$fstype VENDOR=$vendor MODEL=$model" # Print partition name, partition uuid, partition file system type, vendor, model done

Or straight forward(by passing the partition PARTUUID(NOT DISK UUID) to a function):

model_by_partuuid () {
p=$(/bin/readlink -f /dev/disk/by-partuuid/&quot;$1&quot;) # Get partition device /path/name by its PARTUUID
b=$(/bin/lsblk -nldo PKNAME &quot;$p&quot;) # Get partition block device
vendor=$(/bin/lsblk -nlo VENDOR /dev/&quot;$b&quot;) # Get vendor of the block device
model=$(/bin/lsblk -nlo MODEL /dev/&quot;$b&quot;) # Get model of the block device
echo &quot;VENDOR=$vendor MODEL=$model&quot; # Print partition vendor, model 

}

Use this function like so:

model_by_partuuid "partition-uuid-here"

So, your intended script might look something like this:

#/bin/bash

ext4_main_mountpoint="/mnt/ext4/" # Specify EXT4 filesystems main mount point ntfs_main_mountpoint="/mnt/ntfs/" # Specify NTFS filesystems main mount point

"echo" in-front of "mkdir" and "mount" is for dry-run(simulation) ... You need to remove "echo" once you're done testing for the script to actually create mount points and mount partitions.

for f in $(/bin/lsblk -nlo TYPE,NAME | /bin/awk '/part/ {print $2}') # Get partitions only do f="/dev/$f" # Set full path to partition uuid=$(/bin/lsblk -nlo PARTUUID "$f") # Get partition UUID uuidf4="${uuid:0:4}" # Get the first four characters of the partition UUID(for reference ... not used below) uuidl4="${uuid: -4}" # Get the last four characters of the partition UUID(for reference ... not used below) fstype=$(/bin/lsblk -nlo FSTYPE "$f") # Get partition file system type d=$(/bin/lsblk -nldo PKNAME "$f") # Get partition block device d="/dev/$d" # Set full path to block device vendor=$(/bin/lsblk -nlo VENDOR "$d") # Get vendor of the block device vendor=$(/bin/echo "$vendor" | /bin/tr -d '[:space:]') # Trim whitespace model=$(/bin/lsblk -nlo MODEL "$d") # Get model of the block device model=$(/bin/echo "$model" | /bin/tr -d '[:space:]') # Trim whitespace if [ "$fstype" == "ext4" ]; then # Check if the filesystem on the partition is EXT4 echo mkdir -p "$ext4_main_mountpoint$vendor-$model-$uuid" # Create the mount point if it doesn't exist echo mount -U "$uuid" "$ext4_main_mountpoint$vendor-$model-$uuid" # Mount the partition elif [ "$fstype" == "ntfs" ]; then # Check if the filesystem on the partition is NTFS echo mkdir -p "$ntfs_main_mountpoint$vendor-$model-$uuid" # Create the mount point if it doesn't exist echo mount -t "$fstype" -U "$uuid" "$ntfs_main_mountpoint$vendor-$model-$uuid" # Mount the partition else
echo "No rule specified for $f: PARTUUID=$uuid FSTYPE=$fstype VENDOR=$vendor MODEL=$model" # For other filesystem types(not specified above), print partition name, partition uuid, partition file system type, vendor, model fi done

Alternatives

Furthermore, alternative methods of identifying your disks partitions and mounting them automatically to a certain mount point are described in this answer.

Raffa
  • 32,237
  • Thel model and vendor do not appear on each row/partition it finds on hard disks.

    As i said on my original post, this does not work and have explained why in my original post

    – Jono Jul 11 '22 at 14:01
  • @Jono I updated the answer for that. – Raffa Jul 11 '22 at 15:14
  • Thanks i wil give that a go – Jono Jul 11 '22 at 15:22
  • I did +1 a while ago, @Raffa; "${f::-1}" is nice and quick, but not waterproof: I think it fails for partition numbers 10 and higher, and also for nvme and mmcblk drives. But it works for typical SATA drives and USB drives sdxn – sudodus Jul 11 '22 at 19:42
  • 1
    @sudodus It's supposed to be just a template ... But, you are right ... What seems clear and simple to an experienced user, might not be so simple for other users ... I will update the answer in a few minutes to meet your strict high standards :-) ... Good morning by the way. – Raffa Jul 12 '22 at 05:16
  • 1
    @sudodus I updated the template to work on all partitions on any disk type ... Please, check and let me know what you think. – Raffa Jul 12 '22 at 05:27
  • 1
    Yes @Raffa, I did a quick test of your function model_by_partuuid, and it works also for my nvme drive (I did not test it extensively, but I think it is waterproof now) :-) – sudodus Jul 12 '22 at 11:32
  • O you have updated this since i last saw. i will give this a go . thanks for the detailed response – Jono Jul 13 '22 at 18:09
3

I have done something similar before, modified it and thought that the following shellscript can do what you want, or at least similar to what you want. It should be possible to modify and include in your scripts.

#!/bin/bash

inversvid="\0033[7m" resetvid="\0033[0m"

function lister {

sdx=$(<<< "$1" sed 's/[0-9]$//') #echo "sdx=$sdx" nvmex=$(<<< "$sdx" grep -o '.[0-9]') #echo "nvmex=$nvmex" if [ "$nvmex" != "" ] then drive="$nvmex" else drive="$sdx" fi #echo "drive=$drive"

model=$(lsblk -ndo model "$drive"| sed 's/ *$//') partition=$(lsblk -no name,uuid "$1")

len=$(( (${#model} + ${#partition} - 13)/2 )) #echo len=$len leng="" for ((i=0;i<len;i++)); do leng="${leng} ";done echo "name${leng}uuid${leng}model" echo -e "$partition ${inversvid}$model$resetvid" } ########################################################################

main

########################################################################

if [ $# -eq 1 ] then echo "checking for specific UUID" else echo "scanning for all UUIDs" fi

for name in $(lsblk -nlo name) do type=$(lsblk -nlo type "/dev/$name") if [ "$type" == "part" ] then uuid=$(lsblk -nlo uuid "/dev/$name") if [ $# -eq 1 ] && [ "$uuid" == "$1" ] then lister "/dev/$name" break elif [ $# -ne 1 ] && [ "$uuid" != "" ] then lister "/dev/$name" fi fi done

Example:

$ ./uuid2model 8ce17a86-5b31-45cc-a89d-338f618eebad
checking for specific UUID
name                           uuid                           model
nvme0n1p1 8ce17a86-5b31-45cc-a89d-338f618eebad KINGSTON SA2000M8250G

Without parameter it prints the drive models for all UUIDs found.

sudodus
  • 46,324
  • 5
  • 88
  • 152