打印匹配前后的文本,从特定的开头到结束字符串

打印匹配前后的文本,从特定的开头到结束字符串

我正在尝试从一个包含数千个条目的大型 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变量。此后,我们将当前行 ( ) 添加(附加)$0gene变量中,并在旧值和添加值之间使用换行符(ORS = 输出记录分隔符)。
  • 如果当前基因包含您要查找的基因名称,请设置标志found
  • 我们必须使用相当丑陋的方式/\/\//来搜索//.当我们看到一个基因时,我们检查当前的基因是否是我们正在寻找的基因,如果是,则打印它。然后重置继续搜索。如果您确定要查找的基因在文件中只出现一次(或者您只想第一次出现),则可以从此处退出。

答案2

当每个基因record 指定它在 之间LOCUS...//,那么你可以这样做:

gawk '/gene2/{printf $0 RS}' RS='\n//\n' infile

我们定义了RS每个记录都以唯一值结尾,例如“ \newline //\newline”(仅包含 的行//),然后对于与 printf 匹配的每个记录,/gene2/记录$0并恢复回来RS

笔记: 要管理RS何时包含前导/尾随空格(空格/制表符),您可以更改为RS='\n( |\t)*//( |\t)*\n',但需要使用RTGNUawk 扩展)以保留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 将根据我们是否在保留区域前面看到换行符来触发打印活动。

相关内容