拆分列并将新列分别附加到表

时间:2020-07-02 21:01:22

标签: bash

我有一个名为baitmap.txt的表。在$ 5中,不同的基因名称用“,”分隔。

baitmap.txt

1   831895  848168  218 RP11-54O7.1-001
1   848169  850618  219 RP11-54O7.2-001
1   850619  874081  220 SAMD11-011,SAMD11-003,SAMD11-010,SAMD11-001,SAMD11-004
1   889424  903640  223 NOC2L-001
1   903641  927394  224 C1orf170-001,C1orf170-201
1   927395  936954  225 HES4-002,HES4-001,HES4-004
1   943677  957199  228 RP11-54O7.11-001
1   1005127 1034268 234 RNF223-201
1   1049052 1062659 239 C1orf159-002,C1orf159-001,C1orf159-004,C1orf159-009,C1orf159-011,C1orf159-017,C1orf159-016,C1orf159-203,C1orf159-201,C1orf159-204,C1orf159-202
1   1096739 1107115 246 MIR200B-201

我想在$ 5中拆分名称,然后将新列分别合并到前面的4列中。所以它应该像这样:

1   831895  848168  218 RP11-54O7.1-001
1   848169  850618  219 RP11-54O7.2-001
1   850619  874081  220 SAMD11-011
1   850619  874081  220 SAMD11-003
1   850619  874081  220 SAMD11-010
1   850619  874081  220 SAMD11-001
1   850619  874081  220 SAMD11-004
1   889424  903640  223 NOC2L-001
1   903641  927394  224 C1orf170-001
1   903641  927394  224 C1orf170-201

5 个答案:

答案 0 :(得分:5)

awk '{split($5, a, ","); $5=""; for( k in a) print $0, a[k]}' baitmap.txt

请注意,awk对数组进行哈希处理,以便置换顺序。如果那很重要,您可以这样做:

awk '{n = split($5, a, ","); $5=""; for(k=1; k<=n; k++) print $0, a[k]}' baitmap.txt

答案 1 :(得分:2)

使用普通bash:

while read -ra fields; do
    # split the last field into the "values" array
    IFS=, read -ra values <<< "${fields[-1]}"
    for val in "${values[@]}"; do
        fields[-1]=$val
        echo "${fields[*]}"
    done
done < baitmap.txt

这需要bash v4.3 +分配给fields[-1]。要使用较旧的bash(例如,在Mac上为/ bin / bash),

while read -ra fields; do
    len=${#fields[@]}
    IFS=, read -ra values <<< "${fields[len-1]}"
    for val in "${values[@]}"; do
        fields[len-1]=$val
        echo "${fields[*]}"
    done
done < baitmap.txt

答案 2 :(得分:0)

我是在几行BAT中完成此操作的(仅限于Dos / Windows)

@echo off
for /F "tokens=1-5" %%a in (baitmap.txt) do (
    for %%i in (%%e) do (
        echo %%a %%b %%c %%d %%i
    )
)

输出

1 831895 848168 218 RP11-54O7.1-001
1 848169 850618 219 RP11-54O7.2-001
1 850619 874081 220 SAMD11-011
1 850619 874081 220 SAMD11-003
1 850619 874081 220 SAMD11-010
1 850619 874081 220 SAMD11-001
1 850619 874081 220 SAMD11-004
1 889424 903640 223 NOC2L-001
1 903641 927394 224 C1orf170-001
1 903641 927394 224 C1orf170-201
1 927395 936954 225 HES4-002
1 927395 936954 225 HES4-001
1 927395 936954 225 HES4-004
1 943677 957199 228 RP11-54O7.11-001
1 1005127 1034268 234 RNF223-201
1 1049052 1062659 239 C1orf159-002
1 1049052 1062659 239 C1orf159-001
1 1049052 1062659 239 C1orf159-004
1 1049052 1062659 239 C1orf159-009
1 1049052 1062659 239 C1orf159-011
1 1049052 1062659 239 C1orf159-017
1 1049052 1062659 239 C1orf159-016
1 1049052 1062659 239 C1orf159-203
1 1049052 1062659 239 C1orf159-201
1 1049052 1062659 239 C1orf159-204
1 1049052 1062659 239 C1orf159-202
1 1096739 1107115 246 MIR200B-201

答案 3 :(得分:0)

由于该问题最初被标记为C,因此似乎应该这样做:

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

static void
process_line(const char *line)
{
        const char *b = line;
        int p = 1;
        for(int field = 0; *b; b++) {
                if( p && !isspace(*b) && ++field == 5 ) {
                        break;
                }
                p = isspace(*b);
        }
        int len = b - line;
        const char *s = b;
        for( ; *b; b++ ) {
                if( *b == ',' || *b == '\n' ) {
                        fwrite(line, 1, len, stdout);
                        fwrite(s, 1, b - s, stdout);
                        putchar('\n');
                        s = b + 1;
                }
        }
}

int
main(int argc, char *const argv[])
{
        (void)argc;
        (void)argv;
        char *line = NULL;
        size_t s;
        while( getline(&line, &s, stdin) != -1 ) {
                process_line(line);
        }
        free(line);
        return 0;
}

答案 4 :(得分:0)

另一个bash变体

while read line; do
    first="${line% *}"
    last="${line##* }"
    printf "$first ${last//,/\\n$first }\n"
done < baitmap.txt