有没有可以用来从文件中提取序列的 Linux 命令?例如,一个文件包含一百万行,我们只想从该文件中随机采样 200 个字符的序列(不考虑标头)。
对于随机,我的意思是每 200 个序列都有相同的被选择概率,并且选择的子串都不重复。
我正在考虑从这样的 fasta 文件中随机提取 200 个字符的序列(不考虑标头):
>NC_001416.1 Enterobacteria phage lambda, complete genome
GGGCGGCGACCTCGCGGGTTTTCGCTATTTATGAAAATTTTCCGGTTTAAGGCGTTTCCGTTCTTCTTCG
TCATAACTTAATGTTTTTATTTAAAATACCCTCTGAAAAGAAAGGAAACGACAGGTGCTGAAAGCGAGGC
TTTTTGGCCTCTGTCGTTTCCTTTCTCTGTTTTTGTCCGTGGAATGAACAATGGAAGTCAACAAAAAGCA
GCTGGCTGACATTTTCGGTGCGAGTATCCGTACCATTCAGAACTGGCAGGAACAGGGAATGCCCGTTCTG
CGAGGCGGTGGCAAGGGTAATGAGGTGCTTTATGACTCTGCCGCCGTCATAAAATGGTATGCCGAAAGGG
ATGCTGAAATTGAGAACGAAAAGCTGCGCCGGGAGGTTGAAGAACTGCGGCAGGCCAGCGAGGCAGATCT
CCAGCCAGGAACTATTGAGTACGAACGCCATCGACTTACGCGTGCGCAGGCCGACGCACAGGAACTGAAG
AATGCCAGAGACTCCGCTGAAGTGGTGGAAACCGCATTCTGTACTTTCGTGCTGTCGCGGATCGCAGGTG
AAATTGCCAGTATTCTCGACGGGCTCCCCCTGTCGGTGCAGCGGCGTTTTCCGGAACTGGAAAACCGACA
TGTTGATTTCCTGAAACGGGATATCATCAAAGCCATGAACAAAGCAGCCGCGCTGGATGAACTGATACCG
GGGTTGCTGAGTGAATATATCGAACAGTCAGGTTAACAGGCTGCGGCATTTTGTCCGCGCCGGGCTTCGC
TCACTGTTCAGGCCGGAGCCACAGACCGCCGTTGAATGGGCGGATGCTAATTACTATCTCCCGAAAGAAT
CCGCATACCAGGAAGGGCGCTGGGAAACACTGCCCTTTCAGCGGGCCATCATGAATGCGATGGGCAGCGA
CTACATCCGTGAGGTGAATGTGGTGAAGTCTGCCCGTGTCGGTTATTCCAAAATGCTGCTGGGTGTTTAT
GCCTACTTTATAGAGCATAAGCAGCGCAACACCCTTATCTGGTTGCCGACGGATGGTGATGCCGAGAACT
TTATGAAAACCCACGTTGAGCCGACTATTCGTGATATTCCGTCGCTGCTGGCGCTGGCCCCGTGGTATGG
CAAAAAGCACCGGGATAACACGCTCACCATGAAGCGTTTCACTAATGGGCGTGGCTTCTGGTGCCTGGGC
GGTAAAGCGGCAAAAAACTACCGTGAAAAGTCGGTGGATGTGGCGGGTTATGATGAACTTGCTGCTTTTG
ATGATGATATTGAACAGGAAGGCTCTCCGACGTTCCTGGGTGACAAGCGTATTGAAGGCTCGGTCTGGCC
AAAGTCCATCCGTGGCTCCACGCCAAAAGTGAGAGGCACCTGTCAGATTGAGCGTGCAGCCAGTGAATCC
CCGCATTTTATGCGTTTTCATGTTGCCTGCCCGCATTGCGGGGAGGAGCAGTATCTTAAATTTGGCGACA
AAGAGACGCCGTTTGGCCTCAAATGGACGCCGGATGACCCCTCCAGCGTGTTTTATCTCTGCGAGCATAA
TGCCTGCGTCATCCGCCAGCAGGAGCTGGACTTTACTGATGCCCGTTATATCTGCGAAAAGACCGGGATC
所以我可以获得这样的序列子集作为示例:
GCATACCAGGAAGGGCGCTGGGAAACACTGCCCTTTCAGCGGGCCATCATGAATGCGATGGGCAGCGACTACATCCGTGAGGTGAATGTGGTGAAGTCTGCCCGTGTCGGTTATTCCAAAATGCTGCTGGGTGTTTATGCCTACTTTATAGAGCATAAGCAGCGCAACACCCTTATCTGGTTGCCGACGGATGGTGATGC
答案1
为了能够对随机 200 个字符长度的序列进行多次快速选择,可以方便地保存不带换行符的 fasta 文件副本(也不包括标头)。
< file.fasta tail -n+2 | tr -d '\n' > newfile
因此,您将随机选择起始字符,而无需命中任何换行符和/或进行任何计算来处理它。另外,我假设wc -c < file
(或wc -m
) 并stat -c "%s" file
给出相同的结果(对于通常的内容、区域设置等,请先检查它),所以我们使用stat
返回速度更快的方法。
对于包含字符的文件n
,可用的选择是n-200
,我们从可能的起始位置排除最后 200 个字符,因为它们无法形成 200 个字符的长字符串。
shuf
选择范围的随机数,并且和的1,n-200
组合将提取字符串。head
tail
-c
n=$(stat -c "%s" newfile)
r=$(shuf -i1-"$((n-200+1))" -n1)
< newfile tail -c+"$r" | head -c200
你可以多次调用它以获得许多不同的结果独立的随机选择,这意味着甚至相同或重叠的序列。
如果您希望您的选择遵循其他标准,例如不在文件中的同一位置和/或不重叠,则必须从同一shuf
命令解析随机数(具有更高的-n
值)。或者,为了不重叠,丢弃任何与现有值接近 200 的新值。
如果你想随机选择x独立的但是您可以开始生成随机行的独特序列,删除重复项并将其中的 x 保留为head
,例如获取其中的 10 个:
while true; do sh test.sh; printf "\n"; done | awk '!seen[$0]++' | head
答案2
shuf
随机重新排列文件行。如果要随机采样字符,请使用折叠将每个字符排成一行。
fold -w 1 file | shuf -n 200 | tr -d '\n'
tr
将它们重新排成一行。
如果您想跳过标题:
tail -n+2 | fold -w 1 | shuf -n 200 | tr -d '\n'
答案3
不是很高效,但是这会提取序列中 200 字节长度的随机子字符串:
n=200 # number of bytes to extract
num_bytes=$(tail -n+2 file | tr -d '\n' | wc -c) # remove header and newlines, save nr. of bytes
offset=$(shuf -n1 -i0-$(( num_bytes - n ))) # random offset, between 0 and num_bytes - n
tail -n+2 file | tr -d '\n' | # remove header and newlines
dd count="$n" bs=1 skip="$offset" 2>/dev/null # extract substring
我们需要事先知道没有标题和换行符的序列的大小,因此需要对输入文件(或临时文件)进行两次传递。
答案4
我注意到引用的文件大小为 100 万行,1-2GB。复制整个数据以删除换行符,并读取整个数据以使用head
和对其进行剪辑tail
,似乎是不必要的开销。
另一种方法是通过以下方式确定文件大小:
szFn="$( stat --format=%s "${Fn}" )"
然后在文件中生成一系列随机字节偏移量:
shuf --input-range=0-$(( szFn - 1 )) -n "${Count}" | sort -n
并迭代这些偏移量以在所需的查找偏移处读取文件:
dd status=none bs=1 skip="${Skip}" count="${Lth}" if="${Fn}"
此方法可以在大约 1.5 秒内检索 HDD 上 10.8 GB 文件中的 200 个单个随机字符。 (为了比较,wc -l
读取文件需要 2 分 28 秒。)这个问题自从第一次出现以来就已经被澄清了,但是这个方法也可以检索多字节序列。为了处理换行符等,它可能需要一些额外的字节并且只是tr -d '\n'
剪辑这些小部分。
由于预期的文件大小,我检查了一些算术限制。 shuf 最多可处理 64 位无符号整型,Bash 最多可处理 64 位有符号整型,就像 dd 一样。
我还在 shuf 上运行了一些统计数据:它在每次运行时都会进行自我播种,并且生成的序列似乎没有偏差。