Пытаюсь напечатать предыдущую строку в awk, но вместо этого выводится текущая строка дважды

#awk

#awk

Вопрос:

Я пытаюсь использовать awk для имитации uniq -d в определенных полях для печати строки, которая в данный момент читается, а также предыдущей строки, используя первое решение из здесь, но, похоже, оно печатает одну и ту же строку дважды.

Вот пример содержимого файла.

 130 chr1    7237    7238    0k9imgkt
135 chr1    7637    7637    b9gko
138 chr1    7908    7908    kob9g
139 chr1    8045    8045    34e5rg  4r
151 chr1    8329    8329    b
151 chr1    8346    8346    345y46htyh
151 chr1    8346    8346    76jtuj
152 chr1    8358    8358    asfge
  

Вот строка, которую я использовал. Я пытаюсь сравнить строки на основе второго, третьего и четвертого полей; если две или более строк идентичны в этих полях, распечатайте все эти строки целиком. Кроме того, можно с уверенностью предположить, что строки отсортированы на основе полей 1, 2 и 3.

 awk '{prev = $0;   array[$2$3$4]; if(array[$2$3$4] == 2) {print; curr = $0; $0 = prev; print; $0 = curr}}' file
  

Вот каким я хочу быть результат.

 151 chr1    8346    8346    345y46htyh
151 chr1    8346    8346    76jtuj
  

И вот какой результат.

 151 chr1    8346    8346    76jtuj
151 chr1    8346    8346    76jtuj
  

Комментарии:

1. Я допустил ошибку при вводе этой строки; Я исправил ее.

2. Каким должен быть результат, если в конце вашего опубликованного образца ввода появилась строка типа 153 chr1 8045 8045 foo ? Следует ли печатать более раннюю 139 chr1 8045 8045 34e5rg 4r строку, а затем эту новую строку, поскольку оба имеют общие значения $ 2 / $ 3 / $ 4? Если да, то где она должна появиться — перед 151 строкой или после них?

Ответ №1:

Если я правильно понял ваш вопрос, не могли бы вы попробовать следующее.

 awk 'FNR==NR{a[$2$3$4]  ;next} a[($2$3$4)]>1' Input_file Input_file
  

или

 awk '{k=$2 FS $3 FS $4} FNR==NR{a[k]  ;next} a[k]>1'  Input_file Input_file
  

Вывод будет следующим.

 151 chr1    8346    8346    345y46htyh
151 chr1    8346    8346    76jtuj
  

Комментарии:

1. @DangIt, не могли бы вы попробовать это один раз и сообщить мне, поможет ли это вам?

2. Я не уверен, почему, но для меня результатом является пустой файл.

3. @DangIt, не могли бы вы, пожалуйста, сообщить мне, если вы упомянули Input_file 2 раза? Я читаю файл 2 раза.

4. Вы правы; я забыл вставить это во второй раз. Почему мне нужно ввести входной файл дважды? Например, были бы какие-либо преимущества в возможности вызова двух разных входных файлов?

5. Он проверяет, какие ключи существуют несколько раз в файле, а затем на втором проходе печатает их. Циклы teo неэффективны, но позволяют обрабатывать файлы, в которых дубликаты могут быть не смежными.

Ответ №2:

Вы печатаете одну и ту же строку дважды. Не совсем ясно, какой вы хотите видеть логику, но, безусловно, одно из print утверждений должно быть print curr или, возможно print prev . Также одинокий prev ничего не делает и выглядит так, как будто он остался из-за ошибки редактирования.

Возможно, вы ищете что-то вроде

 awk '  array[$2$3$4] >= 2 {
        if(prev)print prev;
        print;
        prev = ""; next }
    { prev = $0 }' file
  

Если это не делает того, что вы хотите, возможно, отредактируйте свой вопрос, чтобы более подробно описать, что, как вы надеетесь, должен делать ваш текущий скрипт; код, который не делает то, что вы хотите, на самом деле не является хорошим способом сообщить, что вы хотите.

Комментарии:

1. Какова цель prev = "" ? Для меня похоже, что {prev = $0} это все равно перезапишется.

2. Это делается для того, чтобы избежать печати prev более одного раза при третьем или четвертом повторении. next Обходит блок, содержащий prev = $0 назначение.

3. a bc -> abc . ab c -> abc . При создании уникальных ключей путем объединения полей вам необходимо включить разделители: {k=$2 FS $3 FS $4} .

4. Это хорошее решение, если поля на самом деле могут быть неоднозначными. Пример данных выглядит так, как будто второе поле не будет сильно отличаться.

5. Я не уверен, что chrN всегда будет заканчиваться цифрой 1 против 2, и что числовые столбцы всегда состоят из 4 цифр против 3 или 5 или чего-то еще, но, возможно, я просто параноик, idk.

Ответ №3:

Вот еще одно решение awk, которое не считывает входной файл дважды и работает, даже если ваш ввод не отсортирован.

 awk '(k = $2 FS $3 FS $4) in a {
  print a[k] $0; a[k] = ""; next
} { a[k] = $0 ORS }' file
  

Комментарии:

1. Используя полный набор данных, он корректно работает для первой пары дубликатов, но после этого выводит только второй дубликат каждой пары дубликатов.

2. @DangIt в это трудно поверить, если только ключи $ 2/3/4 не могут повторяться в последующих строках. Вы должны включить этот вариант использования в свой опубликованный образец ввода / вывода, чтобы люди могли протестировать потенциальные решения на нем.