2015-09-23 7 views
0

Я столкнулся с проблемой, которая превосходит мои базовые знания в области unix и была бы очень признательна за помощь. У меня есть большой файл в следующем формате:Команда LINUX AWK для большого файла

chr1 10495 10499 211 
chr1 10496 10500 1 
chr1 10587 10591 93 
chr1 10588 10592 1 
chr1 10639 10643 4 
chr1 10668 10672 11 
chr1 10697 10701 13 
chr1 10726 10730 8 
chr1 10755 10759 7 
chr1 10784 10788 5 
chr2 10856 10860 4 
chr3 10932 10936 6 
chr3 10933 10937 2 
chr5 11056 11060 4 
chr6 11155 11159 9 

Если значения в столбце один матч и один разница число в колонке два, я хочу суммировать значения в колонке 4 обеих линий и заменить значение столбца 3 в строке 1 со значением столбца 3 в строке 2, иначе просто значения в уникальной строке без изменения любого столбца.

Так что выход я надеюсь на будет выглядеть следующим образом:

chr1 10495 10500 212 
chr1 10587 10592 94 
chr1 10639 10643 4 
chr1 10668 10672 11 
chr1 10697 10701 13 
chr1 10726 10730 8 
chr1 10755 10759 7 
chr1 10784 10788 5 
chr2 10856 10860 4 
chr3 10932 10937 8 
chr5 11056 11060 4 
chr6 11155 11159 9 
+0

ли общие ценности в column1 всегда группируются вместе и значение в colum2 всегда возрастает, как показано в вашем примере ввода? Можете ли вы иметь 3 последовательных номера в столбце2? Если это так, пожалуйста, отредактируйте свой вопрос, чтобы включить его в свой образец ввода/вывода, чтобы мы могли видеть, как вы его обрабатываете. В любом случае ответ будет awk-скриптом - получите книгу «Эффективное программирование Awk», 4-е издание, Арнольд Роббинс, чтобы узнать, как манипулировать текстом в UNIX. –

+0

Что вы делаете с суммой значений в столбце 4? –

+0

Hi Morton, Да, общие значения в столбце 1 всегда группируются вместе, а значения в столбце2 всегда возрастают, потому что я сортировал. В колонке 2 всего 2 последовательных номера. – learner

ответ

2
$ cat tst.awk 
BEGIN { OFS="\t" } 
NR>1 { 
    if (($1==p[1]) && ($2==(p[2]+1))) { 
     print p[1], p[2], $3, p[4]+$4 
     delete p[0] 
     next 
    } 
    else if (0 in p) { 
     print p[0] 
    } 
} 
{ split($0,p); p[0]=$0 } 
END { if (0 in p) print p[0] } 
$ 
$ awk -f tst.awk file 
chr1 10495 10500 212 
chr1 10587 10592 94 
chr1 10639 10643 4 
chr1 10668 10672 11 
chr1 10697 10701 13 
chr1 10726 10730 8 
chr1 10755 10759 7 
chr1 10784 10788 5 
chr2 10856 10860 4 
chr3 10932 10937 8 
chr5 11056 11060 4 
chr6 11155 11159 9 
+1

работает отлично, спасибо много. – learner

+0

Я думаю, что '($ 1 == p [1]) && ($ 2> = p [2]) && ($ 2 <= p [3])' вместо '($ 1 == p [1]) && ($ 2 == (p [2] +1)) 'instevals не всегда +1, что предыдущий .... хотя OP хорошо работает –

+1

@JoseRicardoBustosM. OP хочет проверить «разность чисел в столбце два», поэтому интервал IS всегда +1, а все, что находится в 'p [3]', не имеет значения, это все о '$ 2/p [2]'. –

1

Не проверено близко, но я думаю, что вы хотите:

awk '{split(p,a)} 
    $1==a[1] && a[2]==$2-1{print a[1], a[2], $3, $4 + a[4]; p=""; next} 
    p {print p} {p=$0} 
    END {print}' OFS=\\t input 

В любой стадии (за исключением первой), p содержит значение из предыдущей строки. Вторая строка скрипта проверяет, совпадает ли первое поле в текущей строке с первым полем последней строки и второе поле больше второго поля последней строки. В этом состоянии он печатает первые два поля из предыдущей строки, третий из текущей строки и сумму 4-го поля и переходит к следующей строке. Если они не совпадают, он печатает предыдущую строку. В конце он просто печатает строку.

+1

Ed, хорошая точка. –

+0

Thanks William, Он работает почти идеально, но не распечатывает последнюю строку. Выход: CHR1 CHR1 CHR1 10639 10643 4 CHR1 10668 10672 11 CHR1 10697 10701 13 CHR1 10726 10730 8 CHR1 10755 10759 7 CHR1 10784 10788 5 ChR2 10856 10860 4 CHR3 \t CHR5 11056 11060 4 – learner

+0

@learner - нет, он будет печатать последнюю строку. idk, что вы делаете неправильно во время его запуска. Единственными недостатками, которые я вижу в логике, являются: 1) потому что она не пропускает первую строку для теста, она будет печатать первую строку в маловероятном сценарии, где $ 1 - это то, что оценивалось численно до нуля, а 2 доллара было 1 меньше чем $ 2 на 2-й линии. Попробуйте это после добавления первой строки '0chr 10494 foo bar'.2) Он будет дублировать последнюю строку, если эта строка имеет те же $ 1 и $ 2, что на 1 больше, чем предыдущие $ 2 - попробуйте ее с дополнительной строкой в ​​конце, которая 'chr6 11156 11159 9', –

0

Этого сценарий, я использую, чтобы объединить интервалы в данном транскрипте

awk ' 
    NR==1{ 
     n= split($0, first); 
     c=1; 
     for(i=1; i<=n; i++) d[c, i] = first[i]; 
    } 
    NR>1{ 
     n= split($0, actual); 
     #if(actual[1] != d[c, 1] || actual[2]>d[c, 3]){ #for interval fusion 
     if(actual[1] != d[c, 1] || actual[2]>d[c,2]+1){ #OP requirement 
      c++; 
      for(i=1; i<=n; i++) d[c, i] = actual[i]; 
     }else{ 
      if(actual[3] > d[c,3]) d[c,3] = actual[3]; 
      d[c,4] = d[c,4] + actual[4]; 
     } 
    } 
    END{ 
     for(i=1; i<=c; i++){ 
      print d[i, 1], d[i, 2], d[i, 3], d[i, 4] 
     } 
    }' file 

вы получите:

 
chr1 10495 10500 212 
chr1 10587 10592 94 
chr1 10639 10643 4 
chr1 10668 10672 11 
chr1 10697 10701 13 
chr1 10726 10730 8 
chr1 10755 10759 7 
chr1 10784 10788 5 
chr2 10856 10860 4 
chr3 10932 10937 8 
chr5 11056 11060 4 
chr6 11155 11159 9 
+0

Возможно, вы захотите переписать это с помощью GNU awk 4. *, так как это правда, многомерные массивы сделают ваш код более коротким, более надежным и более легко расширяемым. например цикл контура END может быть 'for (i = 1; i in d; i ++) {для (j = 1; j в d [i]; j ++) ...' поэтому он будет работать для любого количества полей. Вам не нужны все эти конечные точки с запятой, которые вы добавили в некоторые строки, и вам не нужен этот третий аргумент для 'split()', поскольку значение по умолчанию будет делать то, что вы хотите. –