AWK:使用第一行的信息在每一行前面加上

AWK: Use First Line's Info to prepend each line

我在 bash 脚本中有一个 awk 1 衬里。 在做 awk 行时需要帮助... 这是我尝试过的方法,但没有用。

这是我的 data.vcf

. abc hji ran kls
CHR1 0/0 0/0 0/1 0/0
CHR2 0/1 0/0 0/0 0/0
CHR3 1/1 0/0 0/0 0/0
CHR4 0/0 0/0 0/0 1/1

我目前的代码(其他 bash 代码不相关):

awk '{ for (i=1; i<=NF; ++i) { if ($i ~ "/1") print NR==1 $i," ",[=11=]} }' data.vcf

这会打印:

 . abc hji ran kls
 0 CHR1 0/0 0/0 0/1 0/0
 0 CHR2 0/1 0/0 0/0 0/0
 0 CHR3 1/1 0/0 0/0 0/0
 0 CHR4 0/0 0/0 0/0 1/1

我希望它打印这个:

 . abc hji ran kls
 ran CHR1 0/0 0/0 0/1 0/0
 abc CHR2 0/1 0/0 0/0 0/0
 abc CHR3 1/1 0/0 0/0 0/0
 kls CHR4 0/0 0/0 0/0 1/1

基本上,只需在 awk 命令的 $i 前面加上 space,但仅在第一行使用 $i。谢谢你的帮助。

以下 tesprog.awk 脚本将为您提供所需内容:

NR==1 {
    for (i = 2; i <= NF; i++) {
        txt[i] = $i;
    }
    print [=10=];
}
NR > 1 {
    pos = 0;
    for (i = 2; i <= NF; i++) {
        if ($i != "0/0") {
            pos = i;
        }
    }
    print txt[pos]" "[=10=];
}

它使用第一条记录创建一个包含 header 列的数组,然后,对于所有其他记录,它查找 不是 0/0 并存储位置。

然后它使用该位置查找文本以作为该行的前缀。

您给定的测试数据的输出是:

pax> awk -f testprog.awk testprog.in
. abc hji ran kls
ran CHR1 0/0 0/0 0/1 0/0
abc CHR2 0/1 0/0 0/0 0/0
abc CHR3 1/1 0/0 0/0 0/0
kls CHR4 0/0 0/0 0/0 1/1

现在,可能需要进行一些调整,如果我没有完全正确地选择标准,if ($i != "0/0"),但这应该是一个相当小的调整改变。如果有多个可能的匹配项,它还会选择 last 匹配列,因此,如果可能的话,您应该指定在这种情况下所需的行为。


要在 bash 脚本中执行此操作而不需要单独的 awk 脚本,只需使用:

awk '
    NR==1 {
        for (i = 2; i <= NF; i++) {
            txt[i] = $i;
        }
        print [=12=];
    }
    NR > 1 {
        pos = 0;
        for (i = 2; i <= NF; i++) {
            if ($i != "0/0") {
                pos = i;
            }
        }
        print txt[pos]" "[=12=];
    }' testprog.in

或者,如果您真的想要 one-liner,它将是 long-ish 行,而不是 相当 与完全展开的变体一样可读:

awk 'NR==1{for(i=2;i<=NF;i++){t[i]=$i}print [=13=]}NR>1{p=0;for(i=2;i<=NF;i++){if($i!="0/0"){p=i}}print t[p]" "[=13=]}' testprog.in

这是另一种变体:

awk 'NR==1 {for (i=2;i<=NF;i++) a[i]=$i;print;next} {for (i=2;i<=NF;i++) if ($i~"/1") =a[i]FS}1' file
. abc hji ran kls
ran CHR1 0/0 0/0 0/1 0/0
abc CHR2 0/1 0/0 0/0 0/0
abc CHR3 1/1 0/0 0/0 0/0
kls CHR4 0/0 0/0 0/0 1/1

工作原理:

awk '
NR==1 {                     # For line "1"
    for (i=2;i<=NF;i++)     # Loop trough all elements
        a[i]=$i             # Store them in an array "a" using field location as reference
    print                   # Print the line
    next}                   # Do nothing more with line "1"
    {for (i=2;i<=NF;i++)    # Loop trough all fields of all other line
        if ($i~"/1")        # If field location contains "/1"
            =a[i]FS}    # Use that field number and get information from first line
1                           # Print all out
' file                      # Read the file