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;
つまり、出力を取得し、samtools mpileup
2つの別々のコマンドにパイプします。tail -n 5
出力が完全にstdoutで印刷されるのを防ぐためにこれを追加しましたsamtools mpileup
(ただし、出力全体をinputとして使用したいjava -jar varscan
)。
これは最初は機能しているように見えますが、コマンドは完了していないようです(各出力のファイルサイズは、コマンドを実行しなかった場合よりも小さくなりますtee
)。
結局、この2つのjava -jar $varscan
コマンドが決して到着しない入力を待っているというエラーが発生します(ループの2回目の繰り返しを開始する前に)。
これは私が望むことを達成するための最良の方法、つまり2つの別々のコマンドで最初のコマンドの出力を使用することです(理想的には、最初のコマンドの出力をまったく記録/印刷しません)。tee
forループと互換性がありませんか?
よろしくお願いします。
答え1
- 変数参照
- lsを解析しないでください
- オプションですが推奨:スクリプトを簡素化し、繰り返さないでください。 sed を使用してデフォルト名を 2 回生成し、毎回別のサフィックスを追加します。一度作成する方が良いです。これはエラーのリスクを減らし、読みやすさを向上させます。パフォーマンスも少し向上します。あるタスクを一度実行することは「より安い」です。まったく同じ操作を複数回実行するよりも、結果を再利用することです。
- 読みやすさ(例:読み取りと理解するあなたが書いたプログラム)はその一つです。そうでない場合これコードを書くときに最も重要なのは...パフォーマンスが絶対に重要でない限り、より理解しやすい方法でコードを書く優先順位を指定するのが最善です。これは、より多くの改行やインデントを挿入したり、長くて複雑なコマンドをより短く簡単なコマンドに分割することを意味できます。これはスクリプトを書いてデバッグするのに役立ち、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