4

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

6 Answers 6

13

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
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks that works! out of curiosity, so what if i need both columns 2 & 7?
Why not awk '{print $7}'?
Sure, that can be done too. This is just passing column no from command line
6

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 Comments

what is arr in this case?
@sf8193 arr is an array variable which will hold input from stdin splitted by IFS
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

1 Comment

would be easier to read if you use a different separator: 's#.\{18\}\(.*\) */dev/.*#\1#p'
1

Another easy way to do it without awk:

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

The last flag specifies the column.

4 Comments

fails : lsscsi has a fixed column width and visibly not field separator.
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.
this worked for me getting the 3rd column of docker image table in terminal
it fails because the name field may contain spaces, and the path can also contain spaces although rarer
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

Comments

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'

Comments

Your Answer

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.