bash提取字符串段并存储在变量中

时间:2019-09-22 16:42:50

标签: linux bash awk

我想将cppclean的输出转换为类似cppcheck的xml部分,例如:

./bit_limits.cpp:25: static data 'bit_limits::max_name_length'

成为:

<error id="static data" msg="bit_limits::max_name_length">
    <location file="./bit_limits.cpp" line="25"/>
</error>

我从awk开始:

测试代码:

echo "./bit_limits.cpp:25: static data 'bit_limits::max_name_length'" > test
cat test.out | awk -F ":" '{print "<error id=\""$3"\""}
                           {print "msg=\""}{for(i=4;i<=NF;++i)print ":"$i}{print "\">"}
                           {print "<location file=\""$1"\" line=\""$2"\"/>"}
                           {print "</error>"}'

注意:,要运行此命令,您需要将cat命令放回到一行中-为了便于阅读,我将其打印在多行中。

说明: 我正在使用awk并用冒号“:”定界-将行分成有用的块,然后尝试将其构造成XML:

  • {print "<error id=\""$3"\""}-提取错误ID部分
  • {print "msg=\""}{for(i=4;i<=NF;++i)print ":"$i}{print "\">"}-提取消息(替换缺少的冒号,这是所有剩余的部分
  • {print "<location file=\""$1"\" line=\""$2"\"/>"}-提取文件和行,这部分很容易,因为冒号排列很好
  • {print "</error>"}-最终打印结束标签

这很接近,但不太正确,它产生:

<error id=" static data 'bit_limits"
msg="
:
:max_name_length'
">
<location file="./bit_limits.cpp" line="25"/>
</error>

id 字段应仅为“静态数据”,而 msg 字段应为“'bit_limits :: max_name_length'”,但其他情况都可以(我现在不介意将其分成多行-尽管我希望awk每次都不打印新行。

更新 正如@charlesduffy指出的-在上下文中-我想在bash中执行此操作,因为我想将此代码嵌入到makefile(或只是普通的bash脚本)中,以实现最大的可移植性(即无需python或其他工具)。

2 个答案:

答案 0 :(得分:5)

使用bash和正则表达式:

x="./bit_limits.cpp:25: static data 'bit_limits::max_name_length'"
[[ $x =~ (.+):([0-9]+):\ (.+)\ \'(.+)\' ]]

declare -p BASH_REMATCH

输出:

declare -ar BASH_REMATCH='([0]="./bit_limits.cpp:25: static data '\''bit_limits::max_name_length'\''" [1]="./bit_limits.cpp" [2]="25" [3]="static data" [4]="bit_limits::max_name_length")'

BASH_REMATCH数组中的元素1到4包含搜索到的字符串。

来自man bash

  

BASH_REMATCH:一个数组变量,其成员由=~二进制运算符分配给[[条件命令。索引为0的元素是字符串中与整个正则表达式匹配的部分。索引为n的元素是字符串中与第n个带括号的子表达式匹配的部分。此变量为只读。

答案 1 :(得分:1)

可能比需要的复杂得多:

awk '{
    split($1, file_line, ":")
    field = 2
    while(substr($field, 1, 1) != "'\''") {
        id = id " " $field
        ++field
    }
    id = substr(id, 2)
    while(field <= NF) {
        msg = msg " " $field
        ++field
    }
    msg = substr(msg, 3, length(msg) - 1)
    printf("<error id=\"%s\" msg=\"%s\">\n", id, msg)
    printf("    <location file=\"%s\" line=\"%s\">\n", file_line[1], file_line[2])
    print "</error>"
}' test.out