我的输入文件:
{empty line}
Test #1
data
{empty line}
Test #2
data
{empty line}
Test #3
{empty line}
Test #4
data
{empty line}
Test #5
预期输出:
1
2
4
如果使用简单的 bash 脚本在每个测试下都有可用数据,如何获取序列号(在主题标签之后)?
编辑:每个测试下的数据包含很少的值,例如日期、时间、差异等。两个测试之间有多于一根数据线。每个测试之间有一个空行。 “测试”数字始终是从 1 开始的严格递增的正整数序列。
答案1
这将做到这一点:
awk -F ' #' '
function maybePrint() {
if (NR > 1 && NR > lastLine + 1) {print lastSeq}
}
$1 == "Test" {
maybePrint()
lastSeq = $2
lastLine = NR
}
END {
maybePrint()
}
' file
更改要求并不好,但因为我喜欢拼图:如果文件有空行:
sed -n '
/^Test #/ {
s///
=
p
}
$=
' file \
| paste - - \
| awk -F '\t' '
NR > 1 && $1 - prevLine > ($2 ? 2 : 0) {print prev}
{prevLine = $1; prev = $2}
'
答案2
如果数据中没有主题标签:
sed -n 'N;/#.*#/D;s/.*#//;P' file
更清晰的选项:
sed -nE 'N;/(.*#)[0-9]+\n\1/D;s/.*#//;P' file
模式(.*#)[0-9]+\n\1
使用主题标签跟踪重复的行。
答案3
使用 时sed
,您通常会在N;P;D
模式和使用保留空间之间进行选择:
N;P;D
方法
您可以使用该方法在缓冲区中始终保留两行连续的行,方法是N
在开头附加一行,P
仅打印第一行并通过D
删除第一行开始新的循环:
sed '$!N;/\ndata/!D;s/.*#//;P;D'
$!N
如果这还不是最后一行,则追加下一行/\ndata/
匹配第二行为 的双行data
,!
反转匹配并D
开始下一个循环,缓冲区中仅包含第二行。因此,如果第二行不以 开头data
,则继续下一对- 如果我们到达这里,我们知道第二行以 开头
data
,因此s/.*#//
将删除直到 的所有内容#
,P
将打印第一行(现在只是数字),并D
删除下一个循环的第一行(注意两个data
在这种情况下你不知道该怎么做。
等待空间进近
将要打印信息的行保留在h
旧空间中,但仅在触发行上打印:
sed '/data/!{h;d;};x;s/.*#//'
/data/!
寻址所有不包含data
.将这些行放在h
旧空间中并d
删除以重新开始而不输出- 如果我们在这里,
data
确实匹配,那么更改缓冲区以将保存的行获取到模式空间,删除直到with 的x
内容 并通过默认输出打印结果#
s/.*#//
答案4
awk '{a[++i]=$0}/data/{for(x=NR-1;x<=NR;x++)print a[x]}' file| awk -F "#" '/Test/{print $2}'
输出
1
2
4