次の問題についてどなたか助けていただけませんか? 約 40 個の異なる種のディレクトリがあり、それぞれに相同配列を含む数百の配列ファイルがあります。配列ファイルは、各種のディレクトリで同様に名前が付けられています。40 種のディレクトリの同じ名前のファイルを、同様に名前が付けられた単一の配列ファイルに連結したいと考えています。
たとえば、次の 3 つのディレクトリがあります: 「Species1」、「Species2」、「Species3」。これらのディレクトリ内には、似た名前のファイルがあります: 「SequenceA.fasta」、「SequenceB.fasta」、「SequenceC.fasta」。異なる SequenceA.fasta ファイルのすべての内容を、別のディレクトリにある「SequenceA.fasta」という名前の 1 つの新しいファイルに連結する必要があります。どうすればいいですか?
次のループで試してみましたが、失敗しました。ファイルは作成されますが、空です。
ls . | while read FILE; do cat ./*/"$FILE" >> ./final/"$FILE"; done
アドバイスやご協力をいただければ幸いです。
(重複投稿の可能性があったら申し訳ありません。以前、この質問を別のフォーラムに誤って投稿してしまいました)
答え1
この回答には注目すべき点がいくつかあります。
出力を解析するのは一般的には悪い考えですが、代わりにシェルパターンを使用して必要な操作を実行
ls
できます。[glob
[http://mywiki.wooledge.org/ParsingLs]移植性のために nullglob シェル オプションを使用しませんでしたが、これによりスクリプトが若干短くなります。glob パターンが広すぎないように、入力と出力の両方に同じファイル名を使用するように指示します
cat
。そうすると、無限サイズのファイルを作成しようとするため、ハード ドライブがすぐにいっぱいになる可能性があります。のようなパターンを指定して
*.fasta
、どのファイルにも一致しない場合は、リテラル文字列*.fasta
が使用されます。というファイルがある場合
*.fasta
、そのファイルとパターンの違いを確認する 1 つの方法は、そのファイルが読み取り可能かどうかを確認することです。--
不正なファイル名が存在する可能性がある場合は、引数の解析を終了することをお勧めします。
まずは簡単なスクリプトです。
# 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