3

I would like to parse the column elements of the output from the command lsscsi.

Here is a sample output,

# lsscsi

[0:0:0:0]   disk   ATA   VBOX HARDDISK   1.0   /dev/sda
[0:0:1:0]   disk   ATA   VBOX HARDDISK   1.0   /dev/sdb
[1:0:1:0]   disk   ATA   VBOX HARDDISK   1.0   /dev/sdc

Example if I want column 2, my output should be,

disk
disk
disk

If cloumn 7,

/dev/sda
/dev/sdb
/dev/sdc

Thanks

user2887201
  • 317
  • 2
  • 9
  • 19

6 Answers6

11

Use awk like this:

awk -v col=7 '{print $col}' file

Or to print 2 columns:

awk -v col1=2 -v col2=7 '{print $col1, $col2}' file

OR to make it print multiple columns using a colon delimited list:

awk -v col='2:7' '
BEGIN {n = split (col, arr, /:/)}
n {
   for (i=1; i in arr; ++i)
      printf "%s%s", $arr[i], (i < n ? OFS : ORS)
}' file
anubhava
  • 761,203
  • 64
  • 569
  • 643
5

With bash you can use 'read -a', this reads a line from standard input, splits using IFS field separator which has space by default and populates array variable which can be referenced as ${array[n]} (zero based).

while read -a arr; do
    echo "${arr[1]}"
    echo "${arr[6]}"
done
2

Unfortunately lsscsi does not provide consistent parseable output nor the chance to change the field separator as far as I see. With two different harddisks on the same system the column for the device is differing by one! The following code sniplet should give you an idea about what I mean and how I worked around it... at least to get the device which is at the end of the line. To get the product name and the product revision correctly, it could also be an idea to call each device with lssci -c a:b:c:d and then parse this output.

lsscsi > /tmp/tmp$$.out
while read line
do
    echo $line
    echo 012345678901234567890123456789012345678901234567890123456789
    echo 0.........1.........2.........3.........4.........5.........
    ID=$(echo $line | cut -c2)
    TYPE=$(echo $line | cut -c16-18)
    PRODUCT=$(echo $line | sed -n 's/.\{18\}\(.*\) *\/dev\/.*/\1/p')
    DEVICE=$(echo $line | sed -n 's/.\{18\}.*\/dev\/\(.*\)/\1/p')
    echo $ID-$TYPE-$DEVICE-$PRODUCT
done
steviehs
  • 61
  • 2
  • would be easier to read if you use a different separator: `'s#.\{18\}\(.*\) */dev/.*#\1#p'` – phuclv Dec 21 '19 at 05:21
1

Another easy way to do it without awk:

lsscsi | tr -s ' ' | cut -d' ' -f7

The last flag specifies the column.

denten
  • 691
  • 1
  • 6
  • 15
  • fails : lsscsi has a fixed column width and visibly not field separator. – MUY Belgium Feb 10 '20 at 11:01
  • Tested it again on a Linux machine and it works fine. My lsscsi output only has four columns, and therefore I use `-f4` for the final argument. All output is treated as text in the shell, and in this case, we force separation by single space. – denten Apr 27 '20 at 17:46
  • this worked for me getting the 3rd column of docker image table in terminal – misinglink Jun 10 '21 at 06:01
  • it fails because the name field may contain spaces, and the path can also contain spaces although rarer – phuclv May 16 '23 at 09:29
1

Simple examples:
(Each example is independent.)

Select the column 2:

echo -e "[0:0:0:0]   disk   ATA   VBOX HARDDISK   1.0   /dev/sda \
  \n[0:0:1:0]   disk   ATA   VBOX HARDDISK   1.0   /dev/sdb \
  \n[1:0:1:0]   disk   ATA   VBOX HARDDISK   1.0   /dev/sdc" \
  | awk '{print $2}'

Select the column 7:

echo -e "[0:0:0:0]   disk   ATA   VBOX HARDDISK   1.0   /dev/sda \
  \n[0:0:1:0]   disk   ATA   VBOX HARDDISK   1.0   /dev/sdb \
  \n[1:0:1:0]   disk   ATA   VBOX HARDDISK   1.0   /dev/sdc" \
  | awk '{print $7}'

Select the column 2 & 7:

echo -e "[0:0:0:0]   disk   ATA   VBOX HARDDISK   1.0   /dev/sda \
  \n[0:0:1:0]   disk   ATA   VBOX HARDDISK   1.0   /dev/sdb \
  \n[1:0:1:0]   disk   ATA   VBOX HARDDISK   1.0   /dev/sdc" \
  | awk '{print $2, $7}'

Results:

enter image description here

蔡宗容
  • 927
  • 12
  • 9
0

You may want to use the separation in columns with lsscsi : Use perl to insert tab and trim the fields.

lsscsi -g \
| perl -ne 'foreach$c(qw (64 53 47 30 21 13)){
              substr$_,$c,0,"\t"
            };
            s/ *([\t\n])/\1/g;  # trim the fields
            print'

Or one liner :

 lsscsi -g|perl -ne 'foreach$c(qw(64 53 47 30 21 13)){substr$_,$c,0,"\t"};s/ *([\t\n])/\1/g;print'
MUY Belgium
  • 2,330
  • 4
  • 30
  • 46