for ループの tee が期待どおりに動作しない

for ループの tee が期待どおりに動作しない

tee私は次のように for ループで使用しようとしています:

for ea in $(ls *bam)
  do samtools mpileup -f $ref $ea | \
  tee \
  >(java -jar $varscan2 mpileup2indel --output-vcf 1 > vcf/"$(echo $ea | sed s/.bam//)"_mpileup2indel.vcf) \
  >(java -jar $varscan2 mpileup2snp --output-vcf 1 > vcf/"$(echo $ea | sed s/.bam//)"_mpileup2snp.vcf) | \
  tail -n 5
done;

つまり、 の出力を使用し、それを 2 つの別々のコマンドにパイプします。の出力が stdout に完全に印刷されるのを防ぐためにsamtools mpileupを追加しました(ただし、完全な出力を への入力として使用したいです)。tail -n 5samtools mpileupjava -jar varscan

これは最初は機能しているように見えますが、コマンドが完了していないようです (各出力のファイル サイズは、 なしでコマンドを実行した場合よりも小さくなりますtee)。

java -jar $varscan最終的に、2 つのコマンドが (ループの 2 番目の反復を開始する機会を得る前に) 到着しない入力を待機しているというエラーが発生します。

これは、私が求めているもの、つまり最初のコマンドの出力を 2 つの別々のコマンドで使用する (理想的には、最初のコマンドの出力をまったく記録/印刷しない) ための最善の方法ですか? teefor ループとは互換性がありませんか?

前もって感謝します。

答え1

  1. 変数を引用符で囲む
  2. lsを解析しない
  3. オプションですが推奨: スクリプトを簡素化し、同じことを繰り返さないでくださいsed を使用してベース名を 2 回生成し、そのたびに異なるサフィックスを追加しますが、1 回生成する方がバグのリスクが軽減され、読みやすさが向上します (また、パフォーマンスもわずかに向上します。何かを 1 回実行してその結果を再利用する方が、まったく同じ操作を 2 回以上実行するよりも「安価」です)。
  4. 読みやすさ(つまり、読む能力と理解するあなたが書いたプログラム)は、コードを書くときに最も重要なことは、パフォーマンスが絶対的に重要でない場合はいつでも、理解しやすい方法でコードを書くことを優先する方が良いです。これは、より多くの改行やインデントを挿入したり、長くて複雑なコマンドを短くて単純なコマンドに分割したりすることを意味します。これは、今すぐスクリプトを書いてデバッグするのに役立ち、また、X か月 (または数年) 後にスクリプトを再確認する必要がある場合にも理解しやすくなります。
for ea in *.bam; do
  bn="$(basename "$ea" .bam)"
  samtools mpileup -f "$ref" "$ea" |
    tee \
      >(java -jar "$varscan2" mpileup2indel --output-vcf 1 > "vcf/${bn}_mpileup2indel.vcf") \
      >(java -jar "$varscan2" mpileup2snp --output-vcf 1 > "vcf/${bn}_mpileup2snp.vcf") |
    tail -n 5
done

さまざまなインデント レベルに注意してください。たとえば、tee は samtools よりわずかにインデントされ、次に tee の引数は tee よりインデントされ、最後に末尾が tee と同じインデント レベルに戻ります。これにより、どの引数がどのプログラムに属しているか、また、これを読んでいるときにパイプライン (またはループなど) のどこにいるかを理解するのに役立ちます。

ちなみに、パイプ文字の後の行を継続するためのバックスラッシュはオプションです。

あるいは:

outdir="vcf"

for ea in *.bam; do
  bn="$(basename "$ea" .bam)"
  indel="$outdir/${bn}_mpileup2indel.vcf"
  snp="$outdir/${bn}_mpileup2snp.vcf"

  samtools mpileup -f "$ref" "$ea" |
    tee \
      >(java -jar "$varscan2" mpileup2indel --output-vcf 1 > "$indel") \
      >(java -jar "$varscan2" ​mpileup2snp --output-vcf 1 > "$snp") |
 ​   tail -n 5
done

関連情報