如果缺少以下行,则打印该行

如果缺少以下行,则打印该行

这与如果匹配则 awk 打印 2 行但由于我的命令存在无法解决的缓冲问题,我认为更好的方法是完全忽略 stderr 并查找缺少某些行的输出。

所以我的输出将是:

Gathering drive descriptors ...
Gathering data for drive 0 ...
Drive Model: DataTraveler 2.0
Gathering data for drive 1 ...
Drive name:  id1,sd@n5000cca17096
Drive Model: HUH721010AL4204
Drive Speed: 7200 RPMs
Drive Temp:  41 C

Gathering data for drive 2 ...
Drive name:  id1,sd@n5000cca24156
Drive Model: HUH721010AL4204
Drive Speed: 7200 RPMs
Drive Temp:  41 C

Gathering data for drive 3 ...
Drive name:  id1,sd@n5000cca8749
Drive Model: HUH721010AL4204
Gathering data for drive 4 ...
Drive name:  id1,sd@n5000cca19183
Drive Model: HUH721010AL4204
Drive Speed: 7200 RPMs
Drive Temp:  41 C

Gathering data for drive 5 ...
Drive name:  id1,sd@n5000cca4607
Drive Model: HUSMH8010BSS204
Gathering data for drive 6 ...
Drive name:  id1,sd@n5000cca10152
Drive Model: HUH721010AL4204
Drive Speed: 7200 RPMs
Drive Temp:  41 C

我想Drive name为任何缺少Drive SpeedDrive Temp行的驱动器输出 。

输出应该是:

Drive name:  id1,sd@n5000cca8749
Drive name:  id1,sd@n5000cca4607

这超出了我的能力范围,但我确信awk可以做到,但我不打算使用awk,任何完成任务的东西都可以(没有 GNU 工具)。谢谢!

答案1

使用mawkgawk,支持正则表达式和多字符RS(记录分隔符):

awk -v RS='Gathering data' -F'\n' '/Drive name/ && !/Drive Speed/ && !/Drive Temp/{print$(NF-2)}' file

对于awk不支持它们的 an ,可以过滤输入以将其替换为某些单个字符,例如换页符:

awk '/Gathering data/{$0="\f"} 1' file | awk -v RS='\f' -F'\n' '/Drive name/ && !/Drive Speed/ && !/Drive Temp/{print$(NF-2)}'

如果记录中的行没有固定顺序,则可以通过省略 来打印整个记录{print ...},然后可以使用 grep 等过滤输出。

这种方法的优点是可以通过明显的方式修改匹配条件(例如,/Drive Speed: 7200 RPMs/而不是!/foo/ && !/bar/等),它不会将整个文件加载到内存中,最重要的是,不需要您编写一些钝态状态机。

答案2

这是一个 perl 版本:

#!/usr/bin/env bash

perl -ne '
    $l = $_ if (/Drive name:/);
    $s = 1  if (/Drive Speed:/);
    if (/^\s*$/) {
        print "$l\n" if (! defined($s));
        $s = undef;
    }
' "$1"

假设输入文件末尾有一个空行。

运行:test.sh 文件

答案3

RS如果可以依赖字段的顺序,则不需要多字符:

awk '/Drive name/ {if (!LCNT && OLDNM) print OLDNM; OLDNM = $3; LCNT = 0} /Drive (Speed|Temp)/ {LCNT++}' file3
id1,sd@n5000cca8749
id1,sd@n5000cca4607

答案4

每当数据中有标签/名称和值对时,最好创建/使用一个在代码中模仿的数组。同样,当您有多行记录块时。在您上一个问题中,我向您展示了当您的记录以空行分隔时如何处理(请参阅https://unix.stackexchange.com/a/562552/133219),以下是当它们不存在时如何执行此操作以及如何使用更通用的 tag-val 方法而不是依赖于记录中每个值的位置:

$ cat tst.awk
BEGIN { FS=": *" }
/^Gathering data/ { prt() }
{ tags2vals[$1] = $0 }
END { prt() }

function prt() {
    if ( ("Drive name" in tags2vals) && ( !("Drive Speed" in tags2vals) || !("Drive Temp" in tags2vals) ) ) {
        print tags2vals["Drive name"]
    }
    delete tags2vals
}

$ awk -f tst.awk file
Drive name:  id1,sd@n5000cca8749
Drive name:  id1,sd@n5000cca4607

相关内容