Распечатать наборы строк, у которых нет соответствующей пары

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

Пример:

NM00123_rn5_0_1_2
XXXXXXXXXXXXXXXXXXXXXXXXXXX
NM00123_mm10_0_1_2
XXXXXXXXXXXXXXXXXXXXXXXXXXXX
NM00124_rn5_0_1_3
yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
NM00124_mm10_0_1_3
yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
NM00125_rn5_0_1_4
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
NM00126_rn5_0_1_5
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRr
NM00126_mm10_0_1_5
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR

Строка, начинающаяся с NM, - это заголовки, а следующая строка состоит из последовательности алфавитов. Строки заголовка для пары совпадают во всех позициях, кроме rn5 и mm10. Я хочу сохранить только наборы из четырех строк, в которых цифры заголовка NM до и после rn5 и mm10 совпадают для пары. Итак, из приведенного выше примера: Заголовок в строке 1 для rn5 совпадает с заголовком в строке 3 для mm10, так что оставьте это .... но заголовок для rn5 в строке 9 не имеет соответствующей пары, поэтому выведите и заголовок, и следующую строку с последовательность. Я хочу, наконец, иметь файл с равным количеством записей rn5 и mm10.

Я новичок в использовании Unix и был бы очень признателен за помощь в этом. Спасибо.

Ожидаемый результат:

Все приведенные выше записи без строки без соответствующей пары. В данном случае:

NM00125_rn5_0_1_4
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
0
16.01.2017, 18:26
2 ответа

Вот несколько запутанная версия для awk. Некоторые отличия от версии sed от steeldriver:

  1. Она не делает никаких предположений об упорядочивании записей mm10 или rn5
  2. Может иметь дело с отсутствующим rn5 record
  3. Он выводит несопоставленные записи на stderr .
  4. Это намного больше кода: -)

Его можно запустить с помощью:

awk -f my_program.awk infile

Код:

# find and store a header
/^NM.*/ { header = $0; next }

# we found an mm10 line
header ~ /_rn5/ {

    # get the mm10 line that matches this rn5
    mm_match = header
    sub("_rn5", "_mm10", mm_match)

    # if we have a previous mm10, then print the pair
    if (mm_match in headers) {
        print header
        print
        print mm_match
        print headers[mm_match]

        delete headers[mm_match]
    } else {
        headers[header] = $0
    }
    next
}

# we found an mm10 line
header ~ /_mm10/ {

    # get the rn5 line that matches this mm10
    mm_match = header
    sub("_mm10", "_rn5", mm_match)

    # if we have a previous rn5, then print the pair
    if (mm_match in headers) {
        print mm_match
        print headers[mm_match]
        print header
        print

        delete headers[mm_match]
    } else {
        headers[header] = $0
    }
    next
}

Кроме того, этот код можно добавить в конец файла для вывода любых несовпадающих строк в стандартная ошибка :

# The END block is here just to output anything that was unmatched
END {
    # dump the unmatched to stderr
    for (header in headers) {
        print header > "/dev/stderr"
        print headers[header] > "/dev/stderr"
    }
}

Его можно запустить с помощью:

awk -f my_program.awk infile > outfile 2> unmatched

Которая будет выводить запрошенный вывод (через стандартный вывод) в файл вывода , и выводит оставшийся ввод (через стандартную ошибку) в несравнимо . Подробные сведения о перенаправлении ввода-вывода во всем его разнообразии см. В главе о Перенаправления в справочном руководстве Bash.

1
28.01.2020, 02:46

Я думаю то, о чем вы просите, - это что-то что

  • поддерживает 4-строчный буфер; и
  • , если то, что следует за rn5 (до следующей новой строки), совпадает с тем, что следует за mm10 (до следующей, кроме двух, новой строки), напечатайте это и начните заново

Это, вероятно, уродливый способ сделать это, но для иллюстрации с помощью GNU sed :

$ sed -n -e :a \
         -e '$!N; /rn5_\(.*\)\n.*\n.*mm10_\1\n/ {p;b}' \
         -e '/.*\n.*\n.*\n/ D' \
         -e ba infile > outfile

$ diff outfile infile
8a9,10
> NM00125_rn5_0_1_4
> zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
0
28.01.2020, 02:46

Теги

Похожие вопросы