如何连接名称开头相同的文件?
How to concatenate files that have the same beginning of a name?
我有一个目录有几百个*.fasta文件,比如:
Bonobo_sp._str01_ABC784267_CDE789456.fasta
Homo_sapiens_cc21_ABC897867_CDE456789.fasta
Homo_sapiens_cc21_ABC893673_CDE753672.fasta
Gorilla_gorilla_ghjk6789_ABC736522_CDE789456.fasta
Gorilla_gorilla_ghjk6789_ABC627190_CDE891345.fasta
Gorilla_gorilla_ghjk6789_ABC117190_CDE661345.fasta
等等
我想连接属于同一物种的文件,所以在本例中 Homo_sapiens_cc21 和 Gorilla_gorilla_ghjk6789。
几乎每个物种都有不同数量的文件需要连接。
我知道我可以在 unix/linux 中使用一个简单的循环,例如:
for f in thesamename.fasta; do
cat $f >> output.fasta
done
但我不知道如何在循环中指定它应该如何只识别具有相同开头的文件。手动制作数百个文件根本没有意义。
有人知道我该怎么做吗?
如我上面的评论所述,如果您知道所有基本名称并且不介意明确输入它们,一个简单的解决方案是
for f in Homo_sapiens_cc21_*.fasta;
do cat $f >> Homo_sapiens_cc21.fasta;
done
由于情况并非如此,您需要找到一种通用模式来对输出进行分组。根据您的示例(编辑:和您的评论),我看起来这可能是一个单词后跟一个下划线的三次。
假设这个模式是正确的,这可能会满足你的要求:
for f in *.fasta;
do cat $f >> $(echo $f | awk -F'_' '{print "_""_"".fasta"}');
done
解释:
- 列出所有
*,fasta
个文件
- 从前缀构造文件名。我们通过管道
awk
来做到这一点,告诉它通过 _
(-F'_'
) 拆分输入并将其放回一起 ('{print "_""_"".fasta"}'
)
- 最后我们
cat
当前文件并将输出重定向到新建的文件名
我假设命名背后的逻辑是物种是前三个单词,用下划线分隔。我还将假设文件名中没有空格。
一种可能的策略是获取所有物种的列表,然后将具有该 specie/prefix 的所有文件连接成一个文件:
for specie in $(ls *.fasta | cut -f1-3 -d_ | sort -u)
do
cat "$specie"*.fasta > "$specie.fasta"
done
在此代码中,您列出所有 fasta 文件,剪切物种 ID 并生成唯一的物种列表。然后遍历此列表,对于每个物种,将所有以该物种 ID 开头的文件连接到一个具有该物种名称的文件中。
可以使用 find
并避免使用 ls
编写更强大的解决方案,但它们更冗长且可能不太清晰:
while IFS= read -r -d '' specie
do
cat "$specie"*.fasta > "$specie.fasta"
done < <(find -maxdepth 1 -name "*.fasta" -print0 | cut -z -f2 -d/ | cut -z -f1-3 -d_ | sort -zu)
我有一个目录有几百个*.fasta文件,比如:
Bonobo_sp._str01_ABC784267_CDE789456.fasta
Homo_sapiens_cc21_ABC897867_CDE456789.fasta
Homo_sapiens_cc21_ABC893673_CDE753672.fasta
Gorilla_gorilla_ghjk6789_ABC736522_CDE789456.fasta
Gorilla_gorilla_ghjk6789_ABC627190_CDE891345.fasta
Gorilla_gorilla_ghjk6789_ABC117190_CDE661345.fasta
等等
我想连接属于同一物种的文件,所以在本例中 Homo_sapiens_cc21 和 Gorilla_gorilla_ghjk6789。
几乎每个物种都有不同数量的文件需要连接。
我知道我可以在 unix/linux 中使用一个简单的循环,例如:
for f in thesamename.fasta; do
cat $f >> output.fasta
done
但我不知道如何在循环中指定它应该如何只识别具有相同开头的文件。手动制作数百个文件根本没有意义。
有人知道我该怎么做吗?
如我上面的评论所述,如果您知道所有基本名称并且不介意明确输入它们,一个简单的解决方案是
for f in Homo_sapiens_cc21_*.fasta;
do cat $f >> Homo_sapiens_cc21.fasta;
done
由于情况并非如此,您需要找到一种通用模式来对输出进行分组。根据您的示例(编辑:和您的评论),我看起来这可能是一个单词后跟一个下划线的三次。
假设这个模式是正确的,这可能会满足你的要求:
for f in *.fasta;
do cat $f >> $(echo $f | awk -F'_' '{print "_""_"".fasta"}');
done
解释:
- 列出所有
*,fasta
个文件 - 从前缀构造文件名。我们通过管道
awk
来做到这一点,告诉它通过_
(-F'_'
) 拆分输入并将其放回一起 ('{print "_""_"".fasta"}'
) - 最后我们
cat
当前文件并将输出重定向到新建的文件名
我假设命名背后的逻辑是物种是前三个单词,用下划线分隔。我还将假设文件名中没有空格。
一种可能的策略是获取所有物种的列表,然后将具有该 specie/prefix 的所有文件连接成一个文件:
for specie in $(ls *.fasta | cut -f1-3 -d_ | sort -u)
do
cat "$specie"*.fasta > "$specie.fasta"
done
在此代码中,您列出所有 fasta 文件,剪切物种 ID 并生成唯一的物种列表。然后遍历此列表,对于每个物种,将所有以该物种 ID 开头的文件连接到一个具有该物种名称的文件中。
可以使用 find
并避免使用 ls
编写更强大的解决方案,但它们更冗长且可能不太清晰:
while IFS= read -r -d '' specie
do
cat "$specie"*.fasta > "$specie.fasta"
done < <(find -maxdepth 1 -name "*.fasta" -print0 | cut -z -f2 -d/ | cut -z -f1-3 -d_ | sort -zu)