在正则表达式匹配之间切割输出的最有效方法是什么?

时间:2015-12-17 18:51:13

标签: regex linux bash sed

我正在尝试解析

lspci -k 

每台设备输出。换句话说,使用此示例输出:

00:00.0 Host bridge: Intel Corporation 4th Gen Core Processor DRAM Controller (rev 06)
    Subsystem: Gigabyte Technology Co., Ltd Device 5000
00:02.0 VGA compatible controller: Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller (rev 06)
    Subsystem: Gigabyte Technology Co., Ltd Device d000
    Kernel driver in use: i915
00:03.0 Audio device: Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor HD Audio Controller (rev 06)
    Subsystem: Gigabyte Technology Co., Ltd Device 5000
    Kernel driver in use: snd_hda_intel
00:16.0 Communication controller: Intel Corporation 8 Series/C220 Series Chipset Family MEI Controller #1 (rev 04)
    Subsystem: Gigabyte Technology Co., Ltd Device 5001
    Kernel driver in use: mei_me

我希望能够单独遍历每个文件和相关信息。我的正则表达式我用来检测格式??:??。?其他地方是:

grep -E '^[0-9]\w:[0-9]\w\.[0-9]' <<< "$s" | awk -F ' ' '{print $1}'

其中$ s将是此格式列表中有多少设备。我使用这个,因为我有不同格式的非PCI设备。

在这种情况下,我以为我可以得到每个匹配的行号,所以将上述语句输入

grep -n 

然后使用sed从一个区域切换到下一个区域,但我觉得这不是一个有效的方法来解决这个问题。有什么建议?

我正在考虑的另一个解决方案是逐行读取并将空白转换为某个符号:例如。

tr ' ' '%' 

如果一行以此开头,则包含该行。然而,这可能会变得棘手,因为我需要在循环外部使用外部变量。当然我也可以在正则表达式的每个实例之后添加一个\ n然后只需设置:

IFS=$'\n'

鉴于它们是标签,

tr $'\t' 'x'

运作良好。但是,我觉得最有效的方法仍然是以某种方式切割整个部分然后grep我需要的信息,而不是逐行跟随随机变量。

2 个答案:

答案 0 :(得分:3)

以下代码将每个条目从lspci -k拆分为多个部分:

$ /sbin/lspci -k | awk -F'\t' 'NF == 1 { ++n; f = 0 } { a[n, ++f] = $NF } 
END { 
    for (i = 1; i <= n; ++i) { 
        print "section", i; f = 0; while (a[i, ++f]) print a[i, f]; print "" 
    }
}'

通过将输入字段分隔符设置为制表符,我们可以根据它们有多少字段来标识哪些行是新节的开头;每个部分的开头只有1个字段。

END块中的代码演示了使用两个索引节号字段号<可以在数组a中到达每个字段的事实/ em>的。它只是遍历每一个,但你可以自定义逻辑,以便在匹配模式时打印给定字段。

答案 1 :(得分:1)

您是否仅限于lspci -k?例如,请参阅lspci -mmlspci -vkmm,它们更易于解析。

我不确定你的最终目标是什么,但我做了一个你可能会感兴趣的例子。只要你确实限于lspci -k

#!/bin/sh
for slot in `lspci -mm | cut -d " " -f 1`; do
    driver=`lspci -vkmm -s $slot | grep "^Driver:" | cut -f 2`
    if [ -n "$driver" ]; then
        filename=`/sbin/modinfo --filename $driver 2>/dev/null`
        echo $slot $driver $filename
    fi
done