我有 7 个 FastQ 文件,我想通过以下方式将它们合并为一个:
File1 line1
File1 line2
File1 line3
File1 line4
File2 line1
File2 line2
File2 line3
File2 line4
File3 line1
File3 line2
File3 line3
File3 line4
.
.
.
File7 line1
File7 line2
File7 line3
File7 line4
我尝试过粘贴命令,但这给了我以下内容:
File1 line1
File2 line1
File3 line1
.
.
File7 line1
它并不需要我需要的每个文件中的四行。
答案1
我不确定你的交错是什么意思,但如果你只想连接每个文件的前四行,如你的示例所示,请循环它们并使用head
:
for f in ./File[1-7] ; do
head -n 4 "$f"
done > output.file
(如果您使用类似File*
的源模式,请不要命名输出File.out
。如果输出的名称与循环中的 glob 模式匹配,它也会被视为源文件,这会让您获得第一个文件的行两次。)
正如 @steeldriver 在评论中指出的,使用 GNU coreutils 循环是不必要的,你可以这样做:
head -qn 4 ./File[1-7]
(-q
不是标准.)
答案2
以下perl
脚本打开命令行上指定的每个文件,并将每个文件的文件句柄存储在数组中。然后,它一次从每个文件中重复读取和打印最多 4 行(每次检查 EOF,$numopen
每次到达文件的 EOF 时递减计数器),直到没有文件留下未读行。
它不需要关闭文件句柄,因为perl
退出时会自动关闭所有打开的文件。
#!/usr/bin/perl
use strict;
my @filehandles=();
my $files=0;
# open each input file
foreach my $filename (@ARGV) {
open($filehandles[$files++], "<", $filename) ||
die "Couldn't open '$filename': $!";
}
$files--;
my $numopen = $files;
# print up to 4 lines at a time from each file
while ($numopen > 0) {
for my $i (0..$files) {
if (!eof($filehandles[$i])) {
for (1..4) {
if (!eof($filehandles[$i])) {
print scalar readline($filehandles[$i]);
} else {
$numopen--;
}
}
}
}
}
将此脚本保存为,例如,interleave4.pl
使其可执行chmod +x interleave4.pl
并运行为,./interleave4.pl File[1-7]
该脚本已通过使用以下 bash 单行代码创建 7 个文件进行了测试。
for i in {1..7}; do printf "File$i %s\n" {1..10} > "File$i"; done
然后对一些文件进行了编辑,以便它们不具有相同的行数 (10),以确保脚本能够优雅地应对这种情况(它确实如此 - 它只是毫无怨言地移至下一个文件) 。同样,它在处理行数不能被 4 整除的输入文件时也没有问题。
注意:这个脚本可以很容易地修改,这样每次通过主循环时要打印的行数不是硬编码的 4,而是作为命令行上的一个选项。