从Linux Bash命令输出中解析所有列元素

3
我希望能够解析lsscsi命令的列元素。
以下是样本输出:
# 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

如果我想要第二列,我的输出应该是什么?
disk
disk
disk

如果是第七列,
/dev/sda
/dev/sdb
/dev/sdc

谢谢

6个回答

11

使用 awk 的方式如下:

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

或者打印两列:

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

或使用冒号分隔的列表使其打印多列:

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

谢谢,这个可以用!顺便问一下,如果我需要第2列和第7列怎么办? - user2887201
1
为什么不用 awk '{print $7}' - Eric Wolf
当然,这也可以做到。这只是从命令行传递列号。 - anubhava

5

使用bash中的“read -a”命令,可以从标准输入读取一行文本,并将其根据默认的空格IFS字段分隔符进行分割,然后填充数组变量。可以通过${array[n]}(从0开始)引用该数组变量。

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

在这种情况下,arr是什么? - sf8193
@sf8193 arr 是一个数组变量,它将保存从标准输入中由 IFS 分隔的输入。 - Mindaugas Kubilius

2

很遗憾,就我所知,lsscsi没有提供一致的可解析输出,也没有机会更改字段分隔符。在同一系统上使用两个不同的硬盘时,设备列差异为1!以下代码片段应该让您了解我的意思以及我是如何解决它的...... 至少获取位于行末的设备。要正确获取产品名称和产品修订版本,还可以尝试使用“lssci -c a:b:c:d”调用每个设备,然后解析此输出。

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

如果您使用不同的分隔符,阅读起来会更容易:'s#.\{18\}\(.*\) */dev/.*#\1#p' - phuclv

1

另一种不使用 awk 的简单方法:

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

最后一个标志指定列。


失败:lsscsi具有固定的列宽,且没有可见的字段分隔符。 - MUY Belgium
在 Linux 机器上再次测试,运行良好。我的 lsscsi 输出只有四列,因此我使用 -f4 作为最后一个参数。所有输出在 shell 中都被视为文本,在这种情况下,我们通过单个空格强制分隔。 - denten
这对我有效,可以在终端中获取Docker镜像表的第3列。 - misinglink
它失败了,因为名称字段可能包含空格,而路径也可能包含空格,尽管这种情况较少。 - phuclv

1

简单示例:
(每个示例都是独立的。)

选择第二列:

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列:

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}'

选择第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}'

结果:

enter image description here


0

您可能想使用lsscsi中的列分隔符:使用Perl插入制表符并修剪字段。

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'

或者一行代码:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接