使用 sed:
#!/bin/sed -nf
/HD loop$/ {
x
G
N
p
s/.*\n\([^\n]*\)/\1/
}
h
当在行尾(由$
字符表示)找到“HD 循环”时,执行命令块。该命令块首先使用交换命令将保持空间(辅助缓冲区)的内容与模式空间(工作缓冲区)的内容x
交换。正如我们稍后将看到的,我们将保留最后一行读取的保持空间。该G
命令会将保持空间(现在包含当前行)的内容附加到模式空间中,并且该N
命令将读取输入的下一行并将其附加到模式空间中。然后我们可以用p
命令。最后要做的是恢复保持空间。我们使用两个命令来做到这一点。第一个是替代命令,它从模式空间中删除除最后一行之外的所有行。然后我们用命令复制模式空间来保存空间h
。
即使该行与“HD 循环”不匹配,它也会被复制以保留空间。通过这样做,保持空间将始终包含上一行的内容。请注意,由于我们在找到匹配项后设置保留空间的方式,它不能正确识别出现在连续行上的两个匹配项。如果要考虑这一点,则需要进行一些特殊处理:
#!/bin/sed -nf
/HD loop$/ b next
h
:start
n
/HD loop$/ {
x
G
:next
N
p
s/.*\n\([^\n]*\)/\1/
/HD loop$/ b next
d
}
h
b start
对于更完整和通用的版本,我们必须首先考虑在第一行找到“HD loop”时会发生什么。在以前的版本中,它会打印一个空行,然后是“HD loop”行。因为这会使输出混淆,认为 HD 循环实际上前面有一个空行,所以我们必须对此进行特殊处理。特殊处理是使用我们自己的覆盖 sed 的评估循环。
我们start
用命令定义了一个标签:
,它定义了我们循环的开始。然后,在脚本结束时,我们使用b
分支命令跳回到循环的开头。为了完全模仿 sed 的评估循环,start
标签之后的第一个命令是 n
下一个命令,将下一个输入行读入模式空间。
定义了循环后,我们可以处理第一种特殊情况,即第一行以 HD 循环开头的情况。如果是这样,我们必须跳过加载保持空间的内容,因为我们知道它不包含任何有用的数据。next
让我们在命令之后定义一个标签G
以附加保留空间的内容。我们现在可以使用/HD loop/ b next
跳过保持空间操作,只打印当前行和后面的行。
如果第一行不是以“HD loop”开头的,我们必须先将其存储到保持空间中,然后n
再用另一个命令替换它。所以我们用h
命令来做到这一点。
下一个特殊情况是两条“HD 循环”线彼此跟随出现。在这种情况下,在之前版本的块末尾,我们可以检查新读取的行是否包含“HD loop”,如果是,我们可以简单地跳回next
标签以读取另一行并打印它。我们可以根据需要多次执行此操作,处理尽可能多的连续“高清循环”行。
最后一种特殊情况是两条“HD 循环”线被一条线隔开。如果我们保持原样,这种情况将打印两次“HD loop”行之间的行。为了解决这个问题,如果在匹配后立即找到“HD 循环”行,我们必须表现得好像不需要打印保持空间。因为这种情况类似于我们查看输入的第一行时发生的情况,所以我们可以d
在匹配结束时使用删除命令来清除模式空间并重新启动整个脚本。现在它的行为就好像该行是第一个输入行,并且如果匹配之后的行是“HD 循环”行,则不会打印保持空间。
更新:如果你只想要第一个结果,你可以简化一些事情:
#!/bin/sed -nf
/HD loop$/ b next
h
:start
n
/HD loop$/ {
x
G
:next
N
p
q
}
h
b start
现在,我们可以使用q
命令退出,而不是在打印该行后执行所有先前的操作。
希望这会有所帮助=)