打印没有对应对的行集

打印没有对应对的行集

我正在尝试打印一组没有对应对的两行。我最终想删除这些行。

例子:

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 之外的所有位置都匹配。我只想保留四行的集合,即 rn5 和 mm10 匹配之前和之后的 NM 标头数字。因此,从上面的示例来看: rn5 的第 1 行中的标头与 mm10 的第 3 行中的标头匹配,因此保留这一点......但是第 9 行的 rn5 的标头没有相应的对,因此使用以下内容打印标头和下一行顺序。我最终希望有一个包含相同数量的 rn5 和 mm10 条目的文件。

我对使用 Unix 非常陌生,非常感谢您的帮助。谢谢。

预期结果:

以上所有条目都没有相应的对的行。在这种情况下:

NM00125_rn5_0_1_4
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz

答案1

这是 awk 的一个有点复杂的版本。与 Steeldriver 的 sed 版本的一些差异:

  1. mm10它不对或rn5记录的顺序做出任何假设
  2. 它可以处理丢失的rn5记录
  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
}

此外,可以将此代码添加到文件末尾以将任何不匹配的行输出到standard error

# 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

它将把请求的输出(通过标准输出)输出到outfile,并将剩余的输入(通过标准错误)输出到unmatched。有关各种 I/O 重定向的详细信息,请参阅以下章节:重定向在 Bash 参考手册中。

答案2

思考你要求的是

  • 维护一个 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

相关内容