awk 子检查元素并将条目添加到列表

awk sub check element and add entry to a list

我有一个字符串:

1   9790725 .   TTCCTCC T   .   .   ACMG=US;benign_cv=0;ccds_transcript=true;clingen=0
1   9790725 .   TTCCTCC T   .   .   ACMG=US;benign_cv=0;accepted=entry0,entry1;ccds_transcript=true;clingen=1

我需要检查元素 accepted=entry0,entry1,...,entryN; 是否已经在最后一列中。案例:

注意:也可以是单个元素(例如accepted=entry0;里面没有逗号)

我试过这个命令:

awk  -F'\t' ' == "9790725" { if ([=11=] ~ /\;accepted=/) { sub(/accepted=[^;]*/,"accepted=entryX" ) } else { sub(/(accepted=.*)?$/,";accepted=entryX;") } } 1' file

但我只能替换它的值或在不存在时创建它,而不是附加到条目列表中...

如何使用 awk 命令 sub

非常感谢您的帮助!

字符串函数文档:https://www.gnu.org/software/gawk/manual/html_node/String-Functions.html

带子:

If the special character ‘&’ appears in replacement, it stands for the precise substring that was matched by regexp.

awk  '
 == 9790725{
    if ([=10=] ~ /\;accepted=/){
        sub(/accepted=[^;]*/,"&,entryX")
    } 
    else{
        sub(/$/,";accepted=entryX;")
    }
}1' file

结果:

1   9790725 .   TTCCTCC T   .   .   ACMG=US;benign_cv=0;ccds_transcript=true;clingen=0;accepted=entryX;
1   9790725 .   TTCCTCC T   .   .   ACMG=US;benign_cv=0;accepted=entry0,entry1,entryX;ccds_transcript=true;clingen=1

请注意,您还可以使用具有 GNU awk 和 gensub 功能的组。此处不需要,但它可用于更复杂的替换。

gensub() provides an additional feature that is not available in sub() or gsub(): the ability to specify components of a regexp in the replacement text. This is done by using parentheses in the regexp to mark the components and then specifying ‘\N’ in the replacement text, where N is a digit from 1 to 9.


回答您的评论:

假设您有以下输入:

1   9790725 .   TTCCTCC T   .   .   ACMG=US;benign_cv=0;ccds_transcript=true;clingen=0
1   9790725 .   TTCCTCC T   .   .   ACMG=US;benign_cv=0;accepted=entry0,entry1;ccds_transcript=true;clingen=1
1   9790725 .   TTCCTCC T   .   .   ACMG=US;benign_cv=0;accepted=entry0,entry1;ccds_transcript=true;clingen=1;rejected=entry2
1   9790725 .   TTCCTCC T   .   .   ACMG=US;benign_cv=0;accepted=entry0,entry1,entry2;ccds_transcript=true;clingen=1

并且您想添加 entry2 : - 第一行没有接受字段 - 第三个拒绝 entry2 - 第四个已经有 entry2.

我修改了我的脚本来处理这些行:

awk -v entry="entry2" '
( == 9790725) && \
!([=13=] ~ "accepted=[^;]*" entry) && \ 
!([=13=] ~ "rejected=[^;]*" entry){
    if ([=13=] ~ /\;accepted=/){
        sub(/accepted=[^;]*/,"&," entry)
    } 
    else{
        sub(/$/,";accepted=" entry ";")
    }
}1' file

现在,awk 将在附加之前检查条目是否已被接受或拒绝。如果您想要不同的行为,请删除其中一个条件。

1   9790725 .   TTCCTCC T   .   .   ACMG=US;benign_cv=0;ccds_transcript=true;clingen=0;accepted=entry2;
1   9790725 .   TTCCTCC T   .   .   ACMG=US;benign_cv=0;accepted=entry0,entry1,entry2;ccds_transcript=true;clingen=1
1   9790725 .   TTCCTCC T   .   .   ACMG=US;benign_cv=0;accepted=entry0,entry1;ccds_transcript=true;clingen=1;rejected=entry2
1   9790725 .   TTCCTCC T   .   .   ACMG=US;benign_cv=0;accepted=entry0,entry1,entry2;ccds_transcript=true;clingen=1

我认为文件的结构不合适(它看起来像一个带有多个字段分隔符和有时不存在或顺序不同的列的 csv)。使用 json 类型的结构和适合 read/update 它的工具会更容易(而不是 awk)。

您还可以使用 split 函数在 awk 中处理此文件(并在 =;, 上拆分)。我懒得尝试了,希望有更好的文件结构。

$ cat tst.awk
{
    if ( match([=10=],/accepted=[^;]+/) ) {
        [=10=] = substr([=10=],1,RSTART+RLENGTH-1) ",entryX" substr([=10=],RSTART+RLENGTH)
    }
    else {
        [=10=] = [=10=] ";accepted=entryX"
    }
    print
}

$ awk -f tst.awk file
1       9790725 .       TTCCTCC T       .       .       ACMG=US;benign_cv=0;ccds_transcript=true;clingen=0;accepted=entryX
1       9790725 .       TTCCTCC T       .       .       ACMG=US;benign_cv=0;accepted=entry0,entry1,entryX;ccds_transcript=true;clingen=1