gcov
是一个GNU工具链实用程序,它生成代码覆盖率报告(请参阅documentation),格式如下:
-: 0:Source:../../../edg/attribute.c
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:
-: 3:int main (void)
1: 4:{
1: 5: int i, total;
-: 6:
1: 7: total = 0;
-: 8:
11: 9: for (i = 0; i < 10; i++)
10: 10: total += i;
-: 11:
1: 12: if (total != 45)
#####: 13: printf ("Failure\n");
-: 14: else
1: 15: printf ("Success\n");
1: 16: return 0;
-: 17:}
我需要提取从bash脚本执行的行的行号。 $ egrep --regexp='^\s+[1-9]' example_file.c.gcov
似乎返回了相关的行。典型输出的例子是:
1: 978: attr_name_map = alloc_hash_table(NO_MEMORY_REGION_NUMBER,
79: 982: for (k = 0; k<KNOWN_ATTR_TABLE_LENGTH; ++k) {
78: 989: attr_name_map_entries[k].descr = &known_attr_table[k];
78: 990: *ep = &attr_name_map_entries[k];
1: 992:} /* init_attr_name_map */
519: 2085: new_attr_seen = FALSE;
519: 2103: p_attributes = last_attribute_link(p_attributes);
519: 2104: } while (new_attr_seen);
519: 2106: return attributes;
16: 3026:void transform_type_with_gnu_attributes(a_type_ptr *p_type,
16: 3041: for (ap = attributes; ap != NULL; ap = ap->next) {
1: 6979:void process_alias_fixup_list(void)
1: 6984: an_alias_fixup_ptr entries = alias_fixup_list, entry;
我随后必须提取行号字符串。此示例的预期输出为:
978
982
989
990
992
2085
2103
2104
2106
3026
3041
6979
6984
有人可以建议一种可靠,稳健的方法来实现这一目标吗?
注意:
我的想法是消除未放置在角色:
的第一个和第二个实例之间的所有内容,我试图用sed
做到目前为止没有取得多大成功。
答案 0 :(得分:0)
使用awk
:
awk -F: '/ +[0-9]/ {gsub(/ /, "", $2); print $2}' file.gcov
即,使用:
作为字段分隔符,
对于以空格和数字开头的行,
替换第二个字段中的空格并打印第二个字段。
但如果你真的想使用sed
,
你想要一些健壮的东西,你可以这样做:
sed -e '/^ *[0-9][0-9]*: *[0-9][0-9]*:/!d' -e 's/[^:]*: *//' -e 's/:.*//' file.gcov
这里发生了什么?
第一个命令使用模式匹配以1个或多个空格开头的行,后跟1个或多个数字后跟:
后跟1个或多个空格后跟1个或多个数字后跟1 :
。然后是有趣的部分,我们使用!
反转此选择,并使用d
将其删除。我们有效地删除除了我们需要的所有其他行。
第二个命令是一个简单的替换,替换不是:
后跟:
后跟零或更多空格的字符序列。该模式从行的开头应用,因此不需要启动^
,也不需要严格指定1或更多空格,这要归功于之前的命令我们已经知道至少会有之一。
最后一个命令更简单,替换:
及其后的所有内容。
sed
的某些版本会为您提供更紧凑的写作风格的快捷方式,例如[0-9]+
而不是[0-9][0-9]*
,但上面的示例将适用于更广泛的实现(特别是BSD)。