我正在尝试打印一组没有对应对的两行。我最终想删除这些行。
例子:
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 版本的一些差异:
mm10
它不对或rn5
记录的顺序做出任何假设- 它可以处理丢失的
rn5
记录 - 它将把不匹配的记录输出到
stderr
。 - 这是更多的代码:-)
它可以通过以下方式运行:
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