给读者的注释
请在考虑此答案时查看该问题的编辑历史记录;通过问题编辑,一些部分的相关性降低了。
One cat
每个输出文件
出于当前的目的,您可能可以让 shell 通配符完成所有工作(如果R1
or R2
将位于文件名中,而不是目录名中):
set -x # log what's happening!
cat */*R1*.fastq >R1.fastq
cat */*R2*.fastq >R2.fastq
One find
每个输出文件
相比之下,如果文件数量确实很大,您可能需要find
:
find . -mindepth 2 -maxdepth 2 -type f -name '*R1*.fastq' -exec cat '{}' + >R1.fastq
find . -mindepth 2 -maxdepth 2 -type f -name '*R2*.fastq' -exec cat '{}' + >R2.fastq
...这是因为操作系统对命令行长度的限制;这find
上面给出的命令将在每个命令上添加尽可能多的参数cat
为了提高效率,尽可能使用命令,但仍将它们分成多个调用,否则将超出限制。
迭代和测试
如果您确实想迭代所有内容,然后测试名称,请考虑case
作业的声明,这比使用要高效得多grep
仅检查一行:
for f in */*.fastq; do
case $f in
*R1*) cat "$f" >&3
*R2*) cat "$f" >&4
esac
done 3>R1.fastq 4>R2.fastq
注意使用文件描述符 3 和 4 进行写入R1.fastq
and R2.fastq
分别——这样我们只打开输出文件一次(因此截断他们恰好一次)当for
循环开始,并重用这些文件描述符,而不是在每个循环的开头重新打开输出文件cat
。 (也就是说,运行cat
每个文件一次——其中find -exec {} +
避免——总的来说可能是更多的开销)。
操作每个目录
上述所有内容都可以更新为在每个目录的基础上运行,非常简单。例如:
for d in */; do
find "$d" -name R1.fastq -prune -o -name '*R1*.fastq' -exec cat '{}' + >"$d/R1.fastq"
find "$d" -name R2.fastq -prune -o -name '*R2*.fastq' -exec cat '{}' + >"$d/R2.fastq"
done
只有两个重大变化:
- 我们不再指定
-mindepth
,以确保我们的输入文件仅来自子目录。
- 我们排除
R1.fastq
and R2.fastq
来自我们的输入文件,因此我们从不尝试使用相同的文件作为输入和输出。这是先前更改的结果:以前,我们的输出文件不能被视为输入,因为它们不符合最小深度。