【问题标题】:bash: extract executed line numbers from gcov reportbash:从 gcov 报告中提取执行的行号
【发布时间】:2023-04-21 23:14:01
【问题描述】:

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 进行此操作,但到目前为止没有取得多大成功。

【问题讨论】:

  • 如果您对特定于 bash 的代码感到满意,参数扩展将比 sed/awk/etc 其他外部进程/程序更快地完成此操作。 example="123: 456: 789abc#\$&amp;-+)({}\/"; example="${example#*\:}"; echo "${example%\:*}"; 输出:456(作为单行测试,列表需要 for 循环)。

标签: regex bash sed gcov


【解决方案1】:

使用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 个或多个数字和 @987654327 开头的行@。然后是有趣的部分,我们用! 反转这个选择并用d 删除它。我们有效地删除了除我们需要的行之外的所有其他行。

  • 第二个命令是一个简单的替换,替换不是: 的字符序列,后跟:,后跟零个或多个空格。该模式从行首开始应用,因此不需要开始 ^,也不需要严格指定 1 个或多个空格,这要归功于前面的命令,我们已经知道至少会有一个。

  • 最后一个命令更简单,替换 : 及其后面的所有内容。

sed 的某些版本将为您提供更紧凑的写作风格的快捷方式,例如 [0-9]+ 而不是 [0-9][0-9]*,但上面的示例将适用于更广泛的实现(尤其是 BSD)。

【讨论】:

  • 感谢您的回复 Janos,我还没有尝试过,但乍一看似乎不错。您认为哪种解决方案的执行速度最快?
  • @J.Doe 通常管道中的进程越少越好。所以一个 awk/sed 应该比 egrep + sed 更好。此外,虽然你说你喜欢[:] 而不是:,但它可能会为正则表达式解析器创建额外的工作(或者不是,它可能足够聪明,可以透明地转换为:
最近更新 更多