如何仅选择以列中的模式开头的信息并在另一列中打印

如何仅选择以列中的模式开头的信息并在另一列中打印

我有一个数据文件A.tsv(字段分隔符= \t):

id  clade   mutation
243 40A S:ojo,L:juju,S:lili
254     
267 40B J:jijy,S:asel,M:ase

我想在另一列(在新文件中B.tsv)仅打印以 开头的突变S:,如下所示:

id  clade   mutation    S_mutation
243 40A S:ojo,L:juju,S:lili S:ojo,S:lili
254     
267 40B J:jijy,S:asel,M:ase S:asel

我用 awk 尝试了一些命令,但没有结果:

awk -F '\t' 'BEGIN { OFS = FS } NR==1 {$(NF+1)="S_Mutation"} ; NR != 1 { $4 = ($3==^[Ss] ? $4 ) }; 1' A.tsv > B.tsv

你知道该怎么做吗?谢谢

答案1

有了POSIX awk,我们就可以如图所示进行操作。将第三个字段用逗号拆分为行 >1 并选择以 S: 开头的元素,然后用逗号将它们连接起来,使其成为最后+1 字段。

awk -F '\t' '
  BEGIN {
    OFS = FS
    _SEP_ = ","
  }

  NR==1{$(NF+1) = "S_mutation"}

  NR>1&&length($3)>0{
    nf = split($3, a, _SEP_)
    t = ""
    for (i=1; i<=nf; i++) {
      if (a[i] ~ /^S:/) {
        t = t (t=="" ? t : _SEP_) a[i]
      }
    }
    $(NF+1) = t
  }1
' file

同样的事情Perl,但使用正则表达式

perl -lnse '$,="\t";
  print $_,($.==1?q(S_mutation):
  "@{[/(?:\t|,)\KS:[^,]*/g]}"||());
' -- -\"=, ./file

输出:

id   clade  mutation             S-mutation
243  40A    S:ojo,L:juju,S:lili  S:ojo,S:lili
254                              
267  40B    J:jijy,S:asel,M:ase  S:asel

答案2

使用awk(POSIX)。

awk -F "\t" '
BEGIN   { OFS = FS }
NR == 1 { $4 = "S_Mutation" }
NR  > 1 && NF == 3 {
    printf "%s", $0 "\t"
    $0 = $3
    gsub(/[^S]:[^,]*,?/, "")
    sub(/,$/, "")
    print $1
    next
}
1' data.txt
  • 如果行 > 1 且字段数 = 3
    • 打印行,不带尾随换行符
    • 设置行 = 字段 3
    • 删除不以以下字符开头的字符串S:
    • 删除所有结尾的逗号
    • 打印带换行符的字段
    • 处理下一行
  • 别的
    • 打印线

您可能不想打印尾随选项卡,测试$1替换后是否有任何内容,然后打印TAB+ 字段。 (如果您不想在没有S:xxx字段的行上使用尾随制表符。例如:

    # Print line
    printf "%s", $0
    # Set line = field 3
    $0 = $3
    # Replace all N:xxx where N is not S
    gsub(/[^S]:[^,]*,?/, "")
    # Remove trailing comma
    sub(/,$/, "")
    # Print the field
    if ($1 != "")
        print "\t"$1
    else
        print ""
    # Continue with next line
    next

答案3

使用 Perl

perl -F'\t' -lpe '
    push @F, $. == 1 ? "S_mutation" : join ",", grep { /^S:/ } split /,/, $F[2];
    $_ = join "\t", @F
' A.tsv > B.tsv

前任。

$ perl -F'\t' -lpe '
    push @F, $. == 1 ? "S_mutation" : join ",", grep { /^S:/ } split /,/, $F[2];
    $_ = join "\t", @F
' A.tsv | column -t
id   clade  mutation             S_mutation
243  40A    S:ojo,L:juju,S:lili  S:ojo,S:lili
254
267  40B    J:jijy,S:asel,M:ase  S:asel

答案4

如果您不介意使用sed

sed 'h;s/.*[[:space:]]/,/;s/,[^S]:[^,]*//g;x;G;s/\n,/\t/'

请注意,\t仅适用于 GNU sed。对于其他风格,通常通过输入ctrlv然后按 Tab 键来插入文字选项卡。

其概念是将行保存在保留空间中,然后隔离最后一列并删除除突变之外的所有突变S:。然后将其作为最后一列附加到保存的行:

  • h将该行复制到保留空间
  • s/.*[[:space:]]/,/用逗号替换最后一个制表符或空格之前的所有内容,因此保留最后一列,并在前面添加逗号。这个逗号将有助于下一步
  • s/,[^S]:[^,]*//gS:删除除 之外的所有元素
  • x交换持有空间和模式空间,因此G会将新列附加到保留空间中保留的原始列
  • s/\n,/\t/最后替换了附加的换行符和我们通过制表符引入的逗号

相关内容