查找特定行号之前最后一次出现的行号

时间:2011-05-18 07:01:47

标签: xml bash shell sed awk

我有一大堆事件,如:

<event>
...
...multiple lines describing the event
...
</event>
<event>
...
... 
<event>

当出现错误时,我会得到发生错误的行号,该行号始终在事件标记内的某处。我想在发生错误之前处理的事件和错误之后拆分文件。我知道我可以使用

进行拆分
csplit -k filename line_number_to_split_on

我需要做的是找到错误行的前一个事件标记的行号。 文件非常大。例如,我在第1007425行列出了一个错误,并查看了事件标记在1007397行的文件。我想在shell脚本中执行此操作。有什么想法吗?

3 个答案:

答案 0 :(得分:2)

将$ LINE作为发生错误的行号,并将$ FILE作为输入文件,您可以这样做:

$ nl -ba $FILE | sed -n -e '/<event>/p' -e ${LINE}q | tail -1

(您可以在sed中使用'='运算符来获取行号而不是nl,但我更喜欢nl更好而且=不是非常便携。而且,它会插入额外的新行,这有点痛苦。)< / p>

作为尾部管道的替代方案,您可以这样做:

$ nl -ba $FILE | sed -n -e '/<event>/h' -e$LINE'{x; p; q;}'

答案 1 :(得分:1)

您的输入看起来像XML。最好的方法是使用XML解析器。手工解析XML并不是那么有趣。根据XML-Parser,起始行号是元素元数据的一部分。 (例如,SAX是Locator。)

<强>更新

它认为使用正确的工具是个好主意。如果您不能使用XML解析器,则必须为XML子集编写自己的解析器。您应该首先查看XML standard并查看您实际需要的功能。如果您不必支持递归,XML实体和XML CDATA,它将消除很多复杂性。获得此信息后,您的问题就可以得到解答。

答案 2 :(得分:1)

我不确定大文件的性能但是有效。

#!/bin/sh
total=$(cat EVENTFILE |wc -l)
error=$1 ### Line number where error occurred
from=$((total-error))
num=$(tac EVENTFILE|awk '/<event>/{print NR}'|while read n; do
    echo ${n};
    if test ${n} -ge ${from}; then
        break;
    fi;
    done|tail -1)
echo $((total-num+1))

测试数据。

 1  <event>
 2  .
 3  .
 4  .
 5  </event>
 6  <event>
 7  ..
 8  ..
 9  ..
10  </event>
11  <event>
12  ...
13  ...
14  ...
15  </event>

输出

foo@ell:/tmp/test$ ./test.sh 3
1
foo@ell:/tmp/test$ ./test.sh 8
6
foo@ell:/tmp/test$ ./test.sh 14
11