这与如果匹配则 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 Speed
和Drive Temp
行的驱动器输出 。
输出应该是:
Drive name: id1,sd@n5000cca8749
Drive name: id1,sd@n5000cca4607
这超出了我的能力范围,但我确信awk
可以做到,但我不打算使用awk
,任何完成任务的东西都可以(没有 GNU 工具)。谢谢!
答案1
使用mawk
和gawk
,支持正则表达式和多字符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