使用两列中的特定值进行awk替换

时间:2018-09-16 21:57:08

标签: awk

我有一个看起来像这样的文件:

20:60479_C_T 60479 C T  0 0 0 0 0 1 0 1
20:60522_T_TC 60522 T TC        0 0 0 0 0 0 0 
20:60568_A_C 60568 A C  0 0 1 0 0 1 
20:60571_C_A 60571 C A  0 1 0 1 0 0 
20:60579_G_A 60579 G A  0 0 1 0 0 0 

我当前的文件更大,有300万行和3,000列。我想使用列$3$4中的值替换其余列中的01。所需的输出将是:

20:60479_C_T 60479 C T  C C C C C T C T
20:60522_T_TC 60522 T TC        T T T T T T T 
20:60568_A_C 60568 A C  A A C A A C 
20:60571_C_A 60571 C A  C A C A C C 
20:60579_G_A 60579 G A  G G A G G G 

我知道如何在两列中做到这一点:

awk '{d["0"]=$3; d["1"]=$4; print "20", $1, "0", $2, d[$5], d[$6];}' myfile

但是我不知道如何为所有列自动执行此操作,并且避免手动添加所有列

3 个答案:

答案 0 :(得分:1)

$ awk '{d[0]=$3; d[1]=$4; for (i=5; i<=NF; i++) $i=d[$i]} 1' file
20:60479_C_T 60479 C T C C C C C T C T
20:60522_T_TC 60522 T TC T T T T T T T
20:60568_A_C 60568 A C A A C A A C
20:60571_C_A 60571 C A C A C A C C
20:60579_G_A 60579 G A G G A G G G

答案 1 :(得分:0)

gsub中使用awk,您可以尝试以下方法:

$ awk '{d[1]=$1;d[2]=$2;gsub(/0/,$3);gsub(/1/,$4);$1=d[1];$2=d[2];}1' myfile
20:60479_C_T 60479 C T C C C C C T C T
20:60522_T_TC 60522 T TC T T T T T T T
20:60568_A_C 60568 A C A A C A A C
20:60571_C_A 60571 C A C A C A C C
20:60579_G_A 60579 G A G G A G G G

答案 2 :(得分:0)

由于您具有可变的列数,因此您可能可以避免使用类似的东西:

awk <testprog.in '{for (i = 5; i <= NF; i++){$i = $($i+3)}print}'

这里的“魔术”是将$($i+3)的所有值$i分配给i,该值介于5和字段计数(含)之间。

表达式$i+301分别转换为34,因此下一步将评估$3$4(例如第一行中的CT),然后使用它们来替换项目。

您的小型测试用例的输出符合预期:

20:60479_C_T 60479 C T C C C C C T C T
20:60522_T_TC 60522 T TC T T T T T T T
20:60568_A_C 60568 A C A A C A A C
20:60571_C_A 60571 C A C A C A C C
20:60579_G_A 60579 G A G G A G G G

您当然需要使用更大的数据集来检查其性能。在我的盒子上,一个三百万行的文件,每个文件有3000个条目,大约需要半小时。

将其与C程序(尽管公认的快速'n'脏,与您的特定输入数据紧密相关,而我通常认为没有必要进行错误检查)进行比较,则只需大约十分钟。

为完整起见,这是C变体,假设它名为prog.c,则可以使用gcc -o prog prog.c之类的代码进行编译,并使用./prog <testprog.in之类的代码运行:

#include <stdio.h>
#include <ctype.h>

static char buff[102040];

static char *getStr(char *buff, int *pSz) {
    if (*buff == 0) return NULL;

    char *nextBuff = buff;
    while ((nextBuff[0] != 0) && isspace(nextBuff[0])) {
        nextBuff++;
    }
    if (*nextBuff == 0) return NULL;

    *pSz = 0;
    while ((nextBuff[*pSz] != 0) && ! isspace(nextBuff[*pSz])) {
        (*pSz)++;
    }

    return nextBuff;
}

int main(void) {
    char *str, *str3, *str4; int sz, sz3, sz4;

    while (fgets(buff, sizeof(buff), stdin) != NULL) {
        str = getStr(buff, &sz); printf("%*.*s", sz, sz, str);
        str = getStr(str + sz, &sz); printf(" %*.*s", sz, sz, str);
        str3 = getStr(str + sz, &sz3); printf(" %*.*s", sz3, sz3, str3); 
        str4 = getStr(str3 + sz3, &sz4); printf(" %*.*s", sz4, sz4, str4);

        str = getStr(str4 + sz4, &sz);
        while (str != NULL) {
            if (*str == '0') {
                printf(" %*.*s", sz3, sz3, str3);
            } else {
                printf(" %*.*s", sz4, sz4, str4);
            }
            str = getStr(str + sz, &sz);
        }
        printf("\n");
    }
    return 0;
}