我有一个包含行分隔文本的文件:
GCAACACGGTGGGAGCACGTCAACAAGGAGTAATTCTTCAAGACCGTTCCAAAAACAGCATGCAAGAGCG
GTCGAGCCTAGTCCATCAGCAAATGCCGTTTCCAGCAATGCAAAGAGAACGGGAAGGTATCAGTTCACCG
GTGACTGCCATTACTGTGGACAAAAAGGGCACATGAAGAGAGACTGTGACAAGCTAAAGGCAGATGTAGC
由此,我想提取字符 10 到 80,所以:
TGGGAGCACGTCAACAAGGAGTAATTCTTCAAGACCGTTCCAAAAACAGCATGCAAGAGCG
GTCGAGCCT
我已经找到了如何计算文件中的字符:
wc -m file
以及如何获取每行的字符数:
awk '{print substr($0,2,6)}' file
但我找不到办法让字符从 10 到 80。
换行符不算作字符。
有任何想法吗?
是的,这是来自完整基因组的 DNA。我使用以下方法从包含不同支架(本例中为 10 和 11)的 fasta 文件中提取了这段 DNA
awk '/scaffold_10\>/{p=1;next} /scaffold_11/{p=0;exit} p'
最终,我想要一个简单的命令来从指定的脚手架获取 100 到 800 个字符(或类似的字符)。
编辑:问题在这里继续:使用 gff2fasta 代替 bash 脚本从完整基因组中获取部分 DNA 序列
答案1
$ cat file1
GCAACACGGTGGGAGCACGTCAACAAGGAGTAATTCTTCAAGACCGTTCCAAAAACAGCATGCAAGAGCG
GTCGAGCCTAGTCCATCAGCAAATGCCGTTTCCAGCAATGCAAAGAGAACGGGAAGGTATCAGTTCACCG
GTGACTGCCATTACTGTGGACAAAAAGGGCACATGAAGAGAGACTGTGACAAGCTAAAGGCAGATGTAGC
检查每行的长度
$ awk '{print length,$0}' file1
70 GCAACACGGTGGGAGCACGTCAACAAGGAGTAATTCTTCAAGACCGTTCCAAAAACAGCATGCAAGAGCG
70 GTCGAGCCTAGTCCATCAGCAAATGCCGTTTCCAGCAATGCAAAGAGAACGGGAAGGTATCAGTTCACCG
70 GTGACTGCCATTACTGTGGACAAAAAGGGCACATGAAGAGAGACTGTGACAAGCTAAAGGCAGATGTAGC
打印10-80个字符
$ awk '{print substr($0,10,70)}' RS= file1
TGGGAGCACGTCAACAAGGAGTAATTCTTCAAGACCGTTCCAAAAACAGCATGCAAGAGCG
GTCGAGCC
假设输入不包含空行(RS=
启用段落模式其中每条记录都是一个段落(段落由空行序列分隔)),这意味着将整个文件加载到内存中。
答案2
我想知道应该如何处理文件中的换行符。这算不算一个角色?
如果我们只是从字节 10 中取出并打印 71 个字节(A、C、T、G 和换行符),那么 Sato Katsura 解决方案是最快的(这里假设 GNUdd
或兼容status=none
, 替换为2> /dev/null
(尽管这也会隐藏错误消息,如果有的话) )与其他实现):
dd if=file bs=1 count=71 skip=9 status=none
如果应跳过换行,则使用以下命令将其过滤掉tr -d '\n'
:
tr -d '\n' < file | dd bs=1 count=70 skip=9 status=none
如果应跳过 Fasta 标头,则为:
grep -v '^[;>]' file | tr -d '\n' | dd bs=1 count=70 skip=9 status=none
grep -v '^[;>]' file
;
表示跳过所有以或开头的行>
。
答案3
对于字节(因此也适用于示例中的单字节字符):
dd bs=1 skip=9 count=71 < file 2> /dev/null
或者使用 GNU 更有效dd
:
dd iflag=fullblock,skip_bytes,count_bytes skip=9 count=71 status=none < file
对于字符,带有zsh
:
{
IFS= read -ru0 -k9 discard &&
IFS= read -ru0 -k71 text &&
printf %s $text
} < file
(如果文件中的字符少于 80 个,则不会打印任何内容)。
ksh93
并且bash
有一个-N
类似于zsh
s 的选项-k
,但它们不支持 NUL 字符并且一个bash
是越野车。
使用 GNU awk
:
awk -v RS='.{1}' -v ORS= 'NR>=10 {print RT}; NR == 80 {exit}'
我们使用的单个字符不会被视为正则表达式.{1}
。.
另一种选择是转换为每个字符具有固定字节数(并且具有所有可能的字符)的字符编码,例如每个字符具有 4 个字节的 UTF-32LE:
< file iconv -t UTF-32LE |
dd bs=4 skip=9 count=71 2> /dev/null |
iconv -f UTF-32LE
答案4
perl -l -0777pe '
my($start, $stop) = qw/10 80/; $delta = $stop - $start--;
(undef, $_, $a) = unpack "A${start}A${delta}A*";
$_ .= $1 while length() - y/\n/\n/ < $delta and $a =~ /(.)/g;
' scaffolded_file_10