谁能帮我解决以下问题?我有大约 40 个不同物种的目录,每个目录都有 100 个包含直系同源序列的序列文件。每个物种目录的序列文件都以类似的方式命名。我想将 40 个物种目录的同名文件连接成一个名称相似的序列文件。
例如,我有以下 3 个目录:“Species1”、“Species2”、“Species3”。这些目录中包含类似命名的文件:“SequenceA.fasta”、“SequenceB.fasta”、“SequenceC.fasta”。我需要将不同 SequenceA.fasta 文件的所有内容连接到另一个目录中名为“SequenceA.fasta”的新文件中。我该怎么做呢?
我用下面的循环尝试了它,但失败了。文件已创建但为空:
ls . | while read FILE; do cat ./*/"$FILE" >> ./final/"$FILE"; done
感谢您的任何建议或帮助!
(对于任何潜在的交叉发布,我很抱歉,我之前不小心在错误的论坛上发布了这个问题)
答案1
这个答案中有几件事需要注意。
ls
如果您可以使用 shellglob
模式来执行您想要的操作,则解析输出通常是一个坏主意- 请参阅 [http://mywiki.wooledge.org/ParsingLs]。为了可移植性,我没有使用 nullglob shell 选项,但这会使脚本稍微短一些。您希望确保您的全局模式不太宽泛,因此您告诉
cat
输入和输出使用相同的文件名,如果这样做,当您尝试创建无限大小的文件时,您可能会很快填满硬盘驱动器。如果您给出类似的模式
*.fasta
,但它不匹配任何文件,则*.fasta
使用文字字符串。如果您有一个名为的文件
*.fasta
,那么区分该文件与模式之间的区别的一种方法是查看它是否可读。--
如果可能存在恶意文件名,那么结束参数解析是个好主意。
首先是一个简单的脚本。
# Simple script, assumes that "Species1" has all the needed "SequenceX.fasta" files
# Start in the directory containing "Species1", "Species2" etc.
# create output directory
mkdir "final"
# Go into the first directory
cd "Species1"
# Loop over all the files
for i in *".fasta"
do
# join all the like named files in the sibling directories to the output
# use a pattern which doesn't match ../final/$i to get list of files to join.
cat "../Species"*"/$i" > "../final/$i"
done
这假设“Species1”具有所有“SequenceX.fasta”文件。如果不是这种情况,那么您可能需要一个双循环。这更稳健,但更长且更慢。
# Start in the top level and loop over the directories
for dir in */
do
# don't do anything inn the output directory
[ "$dir" = "final" ] && continue
# cd into directory, protecting against rogue directory names
cd "./$dir" || { echo "cd to $dir failed" >&2 ; exit 1 ; }
# loop over the files
for file in *"fasta"
do
# check the file exists, if there are no files matching the pattern
# then the shell will pass the pattern through to the loop
if [ -r "$file" ] ; then
cat -- "$file" >> "../final/$file"
fi
done
cd ".." || { echo "failed to return from $dir" ; exit 1 ; }
done