【问题标题】:Unix/bash: For loops with grep to collapse rowsUnix/bash:使用 grep 的 For 循环折叠行
【发布时间】:2015-03-24 03:21:35
【问题描述】:

我有一个制表符分隔的文件A,如下所示:

nameA GO:0005737 细胞质
nameB GO:0005875 微管相关复合物
nameB GO:0005884 肌动蛋白丝
名称C GO:0005737 细胞质
nameC GO:0005856 细胞骨架
nameC GO:0005524 ATP 结合

..

第一列是基因名称,第二列是 GO id,第三列是该 id 的描述。第一列中的每个标识符可以有一行或多行。

我想创建一个新文件,其中每个基因名称只有一行,所有相关的 GO 术语都在第二列,描述在第三列:

nameA GO:0005737 细胞质
nameB GO:0005875,GO:0005884, 微管相关复合物, 肌动蛋白丝
nameC GO:0005737, GO:0005856, GO:0005524 细胞质、细胞骨架、ATP 结合
...

...GO id 的顺序遵循描述词的顺序,即每行中的第一个 GO id 对应于第一个描述词。

我尝试获取所有基因名称的唯一列表,然后对每个基因名称运行 for 循环 grepping,删除 GO 列并用逗号替换换行符,然后在末尾添加一个新行。

cut -f1 文件A | uniq > 标识符

用于“猫标识符”中的名称
做
    grep "$name" 文件A |切-f2 | tr '\n' ',' | sed 's/$/\n/' >> GOs_collapsed
完成

在此之后,我计划对第三列执行相同的操作,然后使用 paste 将两者与标识符文件放在一起。

但是,上面的这个 bash 脚本不起作用。 GOs_collapsed 中的输出只是一个 GO:s 列表,就像以前一样。

去:0005737
去:0005875
去:0005884
.. 

有什么想法吗?

【问题讨论】:

    标签: bash unix for-loop grep


    【解决方案1】:

    您可以使用 awk one liner 来做到这一点,如下所示:

    awk 'BEGIN {
           FS=OFS="\t"
         } 
         { if (a[$1] == "") { 
              a[$1]=$2; b[$1]=$3 
           } else { 
               a[$1]=a[$1] "," $2; b[$1]=b[$1] "," $3;
           } 
         } END { 
             for (i in a) 
                 print i "\t" a[i] "\t" b[i] 
         }' myfile.txt
    

    【讨论】:

    • 虽然不是“单行”!
    • 这非常有帮助。是否可以将其概括为带有附加列的输入文件?就像第一个右侧的第二个描述列一样。
    • 那就是$4。你想用它做什么?与$3 合并?然后b[$1] = b[$1] "," $4。 (变量名可以不那么不透明。)
    • 我想把它作为输出文件的第四列。
    • 也许我可以添加一个像a[$1]=a[$1] "," $2; b[$1]=b[$1] "," $3; c[$1]=c[$1] "," $4; 这样的变量?
    【解决方案2】:

    读取一个键的所有条目并在看到新键时打印收集的输出。这要求一个键的所有条目都是相邻的,这很容易通过对输入进行排序来实现。

    IFS=$'\t'
    sort fileA |
    while read -r key go desc; do
        if [ "$key" != "$prev" ] && [ "$prev" != "" ]; then
            printf '%s\t%s\t%s\n' "$prev" "${gos#,}" "${descs#,}"
            gos=""
            descs=""
        fi
        gos="$gos,$go"
        descs="$descs,$desc"
        prev="$key"
    done
    printf '%s\t%s\t%s\n' "$key" "${gos#,}" "${descs#,}"
    

    构造${var#prefix} 返回var 的值,其中删除了任何prefix。允许和期待前导逗号简化了主要流程,因此我们不必为新密钥的第一轮特例。

    还要注意while 循环中的管道,这可以避免临时文件和讨厌的for 循环。

    【讨论】:

      【解决方案3】:

      假设输入按每行的第一个字段排序,这应该可以满足您的要求。

      $ cat group.awk
      BEGIN {
          FS=OFS="\t"
      }
      
      function printline(last, col, cols) {
          printf last
          for (i = 2; i <= cols; i++) {
              printf OFS"%s", col[i]
          }
          printf ORS
      }
      
      $1 != last {
          if (last) {
              printline(last, col, cols)
          }
      
          # Reset last and our accumulated fields.
          last=$1
          split("", col)
      }
      
      $1 == last {
          cols = (cols > NF) ? cols : NF
          for (i = 2; i <= NF; i++) {
              col[i] = col[i] (col[i]?",":"") $i
          }
          next
      }
      
      END {
          printline(last, col, cols)
      }
      $ awk -f group.awk fileA
      

      【讨论】:

        【解决方案4】:

        根据你目前的情况:

        cut -f1 -d' '  fileA | uniq | while read name; do
            awk -v name="$name" '$1 == name {print $2}' fileA | paste -s -d','  > GOs
            echo "$name    $(awk -v name="$name" '$1 == name {print $3}' fileA | paste -s -d',' | paste GOs -)"
        done
        

        如果字段由制表符而不是空格分隔,请将 cut -d1 -d' ' 更改为 cut -f1

        【讨论】:

          【解决方案5】:

          您可以通过编程方式做到这一点。

          for name in `cut  -d' ' -f 1 file.txt | uniq`
          do
              line="$name\t"
              grepVal=`grep "$name" file.txt`
              for val in `grep "$name" file.txt | cut -d' ' -f6`
              do
                      line="$line$val, "
              done
              line="$line\t"
              for desc in `grep "$name" file.txt | cut -d' ' -f 11-36`
              do
                      line="$line$desc, "
              done
              echo $line >> GOs_collapsed
          done 
          

          输出

          nameA   GO:0005737,     cytoplasm,
          nameB   GO:0005875, GO:0005884,     microtubule, associated, complex, actin, filament,
          nameC   GO:0005737, GO:0005856, GO:0005524,     cytoplasm, cytoskeleton, ATP, binding,
          

          【讨论】:

            猜你喜欢
            • 2013-06-21
            • 2015-09-23
            • 1970-01-01
            • 2019-11-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-11-29
            相关资源
            最近更新 更多