在某个目录中,我有许多包含一堆文本文件的目录。我正在尝试编写一个脚本,该脚本只将每个目录中文件名为“R1”的文件连接到该特定目录中的一个文件中,另一个文件中包含“R2”的文件。这是我写的,但它没有用。
#!/bin/bash
for f in */*.fastq; do
if grep 'R1' $f ; then
cat "$f" >> R1.fastq
fi
if grep 'R2' $f ; then
cat "$f" >> R2.fastq
fi
done
我没有错误,文件按预期创建,但它们是空文件。谁能告诉我我做错了什么?
感谢大家的快速而详细的回复!我想我的问题并不是很清楚,但我需要脚本只连接每个特定目录中的文件,以便每个目录都有一个新文件(R1和R2)。我试着做了
cat /*R1*.fastq >*/R1.fastq
但它给了我一个模棱两可的重定向错误。我也试过了Charles Duffy的循环,但循环遍历这些目录并做了一个嵌套循环来运行目录中的每个文件,如此
for f in */; do
for d in "$f"/*.fastq;do
case "$d" in
*R1*) cat "$d" >&3
*R2*) cat "$d" >&4
esac
done 3>R1.fastq 4>R2.fastq
done
但它给出了关于')'的意外令牌错误。
如果我错过了一些基本的东西,我提前抱歉,我仍然很吵。
答案 0 :(得分:4)
请在考虑此答案时查看问题的编辑记录;通过问题编辑,几个部分的相关性降低了。
cat
出于目的,您可以让shell globbing完成所有工作(如果R1
或R2
将在文件名中,而不是目录名称:
set -x # log what's happening!
cat */*R1*.fastq >R1.fastq
cat */*R2*.fastq >R2.fastq
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
检查一行更有效:< / p>
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
和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
和R2.fastq
,因此我们绝不会尝试将同一个文件用作输入和输出。这是先前更改的结果:以前,我们的输出文件不能被视为输入,因为它们没有达到最小深度。答案 1 :(得分:1)
您的grep
正在搜索文件内容而不是文件名。你可以用这种方式重写它:
for f in */*.fastq; do
[[ -f $f ]] || continue
if [[ $f = *R1* ]]; then
cat "$f" >> R1.fastq
elif [[ $f = *R2* ]]; then
cat "$f" >> R2.fastq
fi
done
答案 2 :(得分:1)
在forloop中查找可能适合这个:
for i in R1 R2
do
find . -type f -name "*${i}*" -exec cat '{}' + >"$i.txt"
done