我有一大堆事件,如:
<event>
...
...multiple lines describing the event
...
</event>
<event>
...
...
<event>
当出现错误时,我会得到发生错误的行号,该行号始终在事件标记内的某处。我想在发生错误之前处理的事件和错误之后拆分文件。我知道我可以使用
进行拆分csplit -k filename line_number_to_split_on
我需要做的是找到错误行的前一个事件标记的行号。 文件非常大。例如,我在第1007425行列出了一个错误,并查看了事件标记在1007397行的文件。我想在shell脚本中执行此操作。有什么想法吗?
答案 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