【问题标题】:awk sub check element and add entry to a listawk 子检查元素并将条目添加到列表
【发布时间】:2019-12-06 09:13:13
【问题描述】:

我有一个字符串:

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; 是否已经在最后一列中。万一:

  • 已经存在(如示例的第 2 行):在其逗号分隔值列表中添加一个元素(例如 entryX)。 (例如,在示例的第 2 行中从 accepted=entry0,entry1; 获取 accepted=entry0,entry1,entryX;
  • absent(如示例的第 1 行)将其添加为 accepted=entryX;

注意:也可以是单个元素(例如accepted=entry0;,其中不包含逗号)

我试过这个命令:

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

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

如何使用awk 命令sub 来做到这一点?

非常感谢您的任何帮助!

【问题讨论】:

    标签: string awk substring substitution


    【解决方案1】:

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

    带子:

    如果特殊字符“&”出现在替换中,它代表正则表达式匹配的精确子字符串。

    awk  '
    $2 == 9790725{
        if ($0 ~ /\;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() 提供了 sub() 中没有的附加功能 或 gsub():在 替换文本。这是通过在正则表达式中使用括号来完成的 标记组件,然后在替换文本中指定“\N”, 其中 N 是从 1 到 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 : - 第一行没有接受字段 - 第三个拒绝进入2 - 第四个已经有 entry2。

    我调整了我的脚本来处理这些行:

    awk -v entry="entry2" '
    ($2 == 9790725) && \
    !($0 ~ "accepted=[^;]*" entry) && \ 
    !($0 ~ "rejected=[^;]*" entry){
        if ($0 ~ /\;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 类型的结构和适应工具来读取/更新它会更容易(不是awk)。

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

    【讨论】:

    • 谢谢@corentin!那太棒了!如果为了避免重复,我需要在添加之前检查特定的userX 是否已经在列表中?我还有一个字段rejcted=user0,user1,...,userN,所以我不能只在字符串中搜索userX,因为它可能在rejected 字段中。对不起,如果我问的是一个子问题,但这是我现在意识到的。无论如何我都会接受你的回答。
    • @cccnrc 不确定。如果用户已经在acceptedrejected 中,你不应该在这两种情况下都添加它吗?我编辑了一个可以满足您需求的解决方案。
    【解决方案2】:
    $ cat tst.awk
    {
        if ( match($0,/accepted=[^;]+/) ) {
            $0 = substr($0,1,RSTART+RLENGTH-1) ",entryX" substr($0,RSTART+RLENGTH)
        }
        else {
            $0 = $0 ";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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-29
      • 2022-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-10
      • 2014-06-16
      相关资源
      最近更新 更多