我正在尝试从一个包含数千个条目的大型 Genbank 文件中提取条目。对于搜索字符串,我使用了一个独特的基因名称——效果很好。棘手的一点是,我想打印该特定基因的整个条目 - 条目以单词 LOCUS 开头,以 // 结尾,并在其间的某个位置包含基因名称。我知道我可以使用 grep 的标志-A
, -B
, 和-C
来打印n字符串匹配之前/之后的行,但实际条目的长度是可变的。我将如何使用 grep 搜索我的字符串(基因名称),然后打印匹配之前的所有行(包括以“LOCUS”开头的行)以及所有行(包括指示结尾的行)条目,这只是“//”?
我愿意接受所有建议 - 有没有办法让-A
和-B
标志匹配字符串(“LOCUS”和“//”)或类似的东西?我应该改用 awk 吗?
编辑:这是一个简化的输入示例 - 每条记录以“LOCUS”开头并以“//”结尾。此示例包含三个记录:
LOCUS scaffold1|size100
/gene="gene1"
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
//
LOCUS scaffold99|size
/gene="gene2"
CGTTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
//
LOCUS scaffold199|size1000
/gene="gene3"
AGTTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
AGTTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
AGTTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
//
我想搜索“gene2”并打印从比赛前“LOCUS”的第一个实例到比赛后“//”中的第一个实例的文本。理想情况下,我想要以下输出:
LOCUS scaffold99|size
/gene="gene2"
CGTTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
//
答案1
这在以下情况中相当容易awk
:
awk -vtarget=fox '
/LOCUS/ { in_gene = 1 }
in_gene { if (gene == "") gene = $0; else gene = gene ORS $0; }
$0 ~ target { found = 1 }
/\/\// { if (in_gene && found) print gene
gene = ""; in_gene = 0; found = 0
}
'
- 将变量设置
target
为您要搜索的字符串(基因名称)。我用fox
作为例子。 - 当我们看到这个词时
LOCUS
,我们知道我们正在寻找一个基因。 - 只要我们关注一个基因,就积累它的内容。第一行(该
LOCUS
行)刚刚被分配给gene
变量。此后,我们将当前行 ( ) 添加(附加)$0
到gene
变量中,并在旧值和添加值之间使用换行符(ORS = 输出记录分隔符)。 - 如果当前基因包含您要查找的基因名称,请设置标志
found
。 - 我们必须使用相当丑陋的方式
/\/\//
来搜索//
.当我们看到一个基因时,我们检查当前的基因是否是我们正在寻找的基因,如果是,则打印它。然后重置继续搜索。如果您确定要查找的基因在文件中只出现一次(或者您只想第一次出现),则可以从此处退出。
答案2
当每个基因record 指定它在 之间LOCUS...//
,那么你可以这样做:
gawk '/gene2/{printf $0 RS}' RS='\n//\n' infile
我们定义了RS每个记录都以唯一值结尾,例如“ \n
ewline //\n
ewline”(仅包含 的行//
),然后对于与 printf 匹配的每个记录,/gene2/
记录$0
并恢复回来RS
。
笔记:
要管理RS
何时包含前导/尾随空格(空格/制表符),您可以更改为RS='\n( |\t)*//( |\t)*\n'
,但需要使用RT
?(GNUawk 扩展)以保留RS完好无损或直接 printf "//"
。
gawk '/gene2/{printf $0 RT}' RS='\n( |\t)*//( |\t)*\n' infile
从man gawk
:
RS 输入记录分隔符,默认为换行符。
RT 记录终结者。呆呆集RT到与指定的字符或正则表达式匹配的输入文本RS。
?:确定记录结束后,呆呆地设置变量RT到输入中匹配的文本RS。什么时候RS是单个字符,RT包含相同的单个字符。然而,当 RS是一个正则表达式,RT包含与正则表达式匹配的实际输入文本。
答案3
sed -ne '
/^LOCUS/,\|^//|!d
H;/^LOCUS/h
\|^/gene="gene2"|{
s/.*//;x;H
}
\|^//|!d;g
s/^\n//p
' input_file
在职的:
,
¶此处可以使用范围运算符
¶ 首先选择正确的范围,即轨迹的开始和//
结束范围。
¶ 将线路存储在保留空间中。
¶ 当我们遇到gene2 的黄金线时,我们在开头放置一个换行符作为标志,以提醒我们何时打印或不打印。
¶ //
line 将根据我们是否在保留区域前面看到换行符来触发打印活动。