help with bash script to [grep sed cut] smartctl output to desired format

If anyone is good at writing bash scripts, and is inclined to do the following, I am looking to achieve this:

i am horrible at writing bash and more horrible at using cut or sed, and if this can be done with minimal lines in bash I would prefer that than to writing a C program

  smartctl --scan

  /dev/sda -d scsi # /dev/sda, SCSI device
  /dev/sdb -d scsi # /dev/sdb, SCSI device
  /dev/bus/0 -d megaraid,0 # /dev/bus/0 [megaraid_disk_00], SCSI device
  /dev/bus/0 -d megaraid,1 # /dev/bus/0 [megaraid_disk_01], SCSI device
  /dev/bus/0 -d megaraid,2 # /dev/bus/0 [megaraid_disk_02], SCSI device
  /dev/bus/0 -d megaraid,3 # /dev/bus/0 [megaraid_disk_03], SCSI device
  /dev/bus/0 -d megaraid,4 # /dev/bus/0 [megaraid_disk_04], SCSI device
  /dev/bus/0 -d megaraid,5 # /dev/bus/0 [megaraid_disk_05], SCSI device
  /dev/bus/0 -d megaraid,6 # /dev/bus/0 [megaraid_disk_06], SCSI device
  /dev/bus/0 -d megaraid,7 # /dev/bus/0 [megaraid_disk_07], SCSI device

  # 'sdb' not important just always used 'sda' for the following
  # for m = 0 to n per the --scan output giving 0..7 do
  #   smartctl -a -d megaraid,m /dev/sda | grep/sed/cut XXX
  #   where the XXX results in just   `KPM5WRUG3T84 12345678a` being extracted
  #   from the smartctl -a output being this:
  # end for m

=== START OF INFORMATION SECTION ===
Product:              KPM5WRUG3T84
User Capacity:        3,840,755,982,336 bytes [3.84 TB]
Logical block size:   512 bytes
Physical block size:  4096 bytes
LU is resource provisioned, LBPRZ=1
Rotation Rate:        Solid State Device
Form Factor:          2.5 inches
Serial number:        12345678a

So for my 8 disks I’m looking to get this formatted output from the script that I can easily open in excel; this is for disk inventory

0 KPM5WRUG3T84  12345678a
1 KPM5WRUG3T84  12345678b
2 KPM5WRUG3T84  12345678c
3 KPM5WRUG3T84  12345678d
4 KPM5WRUG3T84  12345678d
5 KPM5WRUG3T84  12345678e
6 KPM5WRUG3T84  12345678f
7 KPM5WRUG3T84  12345678g

update: here is the bash I wrote based off Stephen Kitt’s answer below, thanks.

#!/bin/bash

N=`smartctl --scan | grep megaraid | wc -l`

for (( m = 0; m < N; m++ )); do

 echo "$m" $(smartctl -a -d "megaraid,$m" /dev/sda | grep -E '(^Product:|^Serial number:)' | cut -d: -f2)

# this one prints # manuf model serial
# smartctl -a -d "megaraid,$m" /dev/sda -json | jq -r ""$m " + .model_name + " " + .serial_number"

done
Asked By: ron

||

For what you’re doing, I think trying to parse the output of smartctl --scan is the wrong solution. If you want a list of model and serial number for all attached drives, you could do something like:

lsblk -nd -o name,model,serial -Q 'TYPE == "disk"' --json |
  jq -r '.blockdevices[]|[values[]|values]|@csv

Which on my system produces:

"sda","Surge","0172000000001537"
"mmcblk0","0xaa675dbe"
"zram0"
"nvme1n1","Samsung SSD 980 PRO with Heatsink 1TB","S6WSNS0WC09089T"
"nvme0n1","Samsung SSD 980 PRO with Heatsink 1TB","S6WSNS0WC09099P"

That’s ready for importing into your favorite spreadsheet. If it lists devices in which you are not interested, you can just filter those out with grep. E.g:

lsblk -nd -o name,model,serial -Q 'TYPE == "disk"' --json |
  jq -r '.blockdevices[]|[values[]|values]|@csv' |
  grep -Evi 'mmcblk|zram'

Which produces:

"sda","Surge","0172000000001537"
"nvme1n1","Samsung SSD 980 PRO with Heatsink 1TB","S6WSNS0WC09089T"
"nvme0n1","Samsung SSD 980 PRO with Heatsink 1TB","S6WSNS0WC09099P"
Answered By: larsks

This will extract a single drive’s product name and serial number, in your loop:

(echo "$m"; smartctl -a -d "megaraid,$m" /dev/sda |
 grep -Po '^(Product|Serial number):s*K.*') |
paste -s -

This outputs the sequence number, extracts the values in the two relevant lines, and pastes everything into a single line with single space separators.

If your version of smartctl can produce JSON output you might want to parse that with jq instead:

smartctl -a -d "megaraid,$m" /dev/sda -json |
jq -r ""$m " + .model_name + " " + .serial_number"
Answered By: Stephen Kitt

Here’s an extensible awk solution:

# For each MegaRAID device...
for m in $(smartctl --scan | grep megaraid | cut -d, -f2)
do
    # Scan it and report the index, product, and serial number
    smartctl -a -d megaraid,"$m" /dev/sda |
        awk -F': *' -v i="$i" '
            $1=="Product" { p=$2 }
            $1=="Serial number" { printf "%1d %st%sn", i, p, $2; p="" }
        '
done
Answered By: Chris Davies
Categories: Answers Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.