使用awk / sed从具有特定模式的行中提取信息

时间:2019-03-27 15:31:35

标签: awk sed

我有一个这样的文件,即

A   10  20  bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1
A   20  30  bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF

使用下面的命令行,我将信息提取为conf的单独列。

sed -Ei 's/(.*conf=)([^;]*)(;.*)/\1\2\3\t\2/g' my_file

但是,如果conf的末尾有这个符号;有用。否则没有。在这两种情况下以及在放置制表符为空的情况下,如何修改脚本以提取模式?

A   10  20  bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1  XF
A   20  30  bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF  XF

我使用此链接作为参考:https://unix.stackexchange.com/questions/414082/extract-part-of-lines-with-specific-pattern-and-store-in-a-new-field-using-awk-o?noredirect=1&lq=1

6 个答案:

答案 0 :(得分:1)

您实际上可以删除;

sed -iE 's/(.*conf=)([^;]*)(.*)/\1\2\3\t\2/g'  my_file

[^;]*是一个否定的括号表达式,它将仅匹配0个或多个(由于*而定),而不是;字符,因此;不是必须存在于模式本身中,前面的模式已经是“受限制的”。

请参见online sed demo

s="A   10  20  bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1
A   20  30  bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF"
sed -E 's/(.*conf=)([^;]*)(.*)/\1\2\3\t\2/g' <<< "$s"

输出:

A   10  20  bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1 XF
A   20  30  bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF XF

答案 1 :(得分:1)

能否请您按照awk中的说明进行操作。

awk 'match($0,/conf=[^;]*/){print $0,substr($0,RSTART+5,RLENGTH-5);next} 1' Input_file

说明: 现在添加上述代码的说明。

awk '                                        ##Starting awk program here.
match($0,/conf=[^;]*/){                      ##Using match function of awk to match regex from string conf= till semi colon comes.
   print $0,substr($0,RSTART+5,RLENGTH-5)    ##Printing current line and then sub-string whose starting point of RSTART+5 and ending point is RLENGTH-5
   next                                      ##next will skip all further statements from here.
}                                            ##Closing BLOCK for match function here.
1                                            ##Mentioning 1 will print lines, those ones which are not having conf string match so it will simply print them.
'  Input_file                                ##Mentioning Input_file name here.

输出如下。

A   10  20  bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1 XF
A   20  30  bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF XF

答案 2 :(得分:1)

每当您有name = value输入数据时,我发现创建表示该关系的数组(下面的f[name]=value)最简单,最可靠,最灵活等,因此您可以按其名称访问值。根据{{​​1}}的含义:

in case it is empty to put tab

或:

$ awk -F'[[:space:];=]+' -v OFS='\t' '
    {delete f; for (i=5; i<NF; i+=2) f[$i]=$(i+1); print $0, f["conf"]}
' file
A   10  20  bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1     XF
A   20  30  bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF     XF

答案 3 :(得分:1)

您可以尝试Perl单线版

$.get('myapi/getfile?cachebreaker=' + Date.now());

或更短

myapi/getfile?cachebreaker=1553709710447

答案 4 :(得分:1)

我们不应该要求;中的\3,因为它已经在\2的排除字符列表中进行了处理:

sed -Ei 's/(.*conf=)([^;]*)(.*)/\1\2\3\t\2/' my_file

如果需要与;以外的其他字符作为分隔符,请将其包含在\2的字符列表中。这样的字符可能是\t还是空格?

sed -Ei 's/(.*conf=)([^;\t ]*)(.*)/\1\2\3\t\2/' my_file

答案 5 :(得分:1)

此问题所链接的问题或多或少地直接复制of my answer

BEGIN { OFS = FS = "\t" }

function get_attrib_by_name(key,  n,attrib,kv) {
    # Split the attribute field on semi-colons.
    n = split($5, attrib, ";")

    # Loop over the attributes and split each on "=".
    # When we've found the one we're looking for (by key name in "key"),
    # return the corresponding value.
    for (i = 1; i <= n; ++i) {
        split(attrib[i], kv, "=")
        if (kv[1] == key) {
            return kv[2]
        }
    }
}

# Using the above function.
{
    name = get_attrib_by_name("conf")
    print $0, name
}

测试:

$ awk -f script.awk file.gff
A       10      20      bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1 XF
A       20      30      bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF XF