Tee in For-Schleife funktioniert nicht wie erwartet

Tee in For-Schleife funktioniert nicht wie erwartet

Ich versuche, es teein einer For-Schleife wie folgt zu verwenden:

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;

D. h., ich verwende die Ausgabe von samtools mpileupund leite diese in zwei separate Befehle weiter. Ich habe hinzugefügt, tail -n 5um zu verhindern, dass die Ausgabe samtools mpileupvon vollständig auf stdout gedruckt wird (ich möchte java -jar varscanjedoch, dass die vollständige Ausgabe als Eingabe für verwendet wird).

Dies scheint zunächst zu funktionieren, aber der Befehl wird anscheinend nicht abgeschlossen (die Dateigröße für jede Ausgabe ist kleiner, als wenn der Befehl ohne ausgeführt würde tee).

Schließlich erhalte ich eine Fehlermeldung, dass die beiden java -jar $varscanBefehle auf eine Eingabe warten, die nie eintrifft (bevor ich die Chance bekomme, die zweite Iteration der Schleife zu starten).

Ist dies die beste Möglichkeit, mein Ziel zu erreichen, d. h. die Ausgabe des ersten Befehls in zwei separaten Befehlen zu verwenden (idealerweise die Ausgabe des ersten Befehls überhaupt nicht aufzuzeichnen/auszudrucken)? Ist dies teenicht mit For-Schleifen kompatibel?

Dank im Voraus.

Antwort1

  1. Zitieren Sie Ihre Variablen
  2. ls nicht analysieren
  3. optional, aber empfohlen: Vereinfachen Sie Ihr Skript undwiederhole dich nicht. Sie generieren den Basisnamen zweimal mit sed und hängen jedes Mal ein anderes Suffix daran an – es wäre besser, ihn einmal zu generieren – dies würde das Risiko von Fehlern verringern und die Lesbarkeit verbessern (und die Leistung ganz leicht verbessern – es ist „billiger“, etwas einmal zu tun und das Ergebnis wiederzuverwenden, als genau dieselbe Operation zweimal oder öfter durchzuführen).
  4. Lesbarkeit (also die Fähigkeit zu lesen undverstehenein Programm, das Sie geschrieben haben) ist einer von, wenn nichtDiedie wichtigsten Dinge beim Schreiben von Code ... also ist es immer dann besser, wenn die Leistung nicht absolut entscheidend ist, den Code so zu schreiben, dass er leichter zu verstehen ist. Das kann bedeuten, mehr Zeilenumbrüche oder Einrückungen einzufügen oder lange und komplizierte Befehle in kürzere, einfachere Befehle aufzuteilen. Das hilft Ihnen, das Skript JETZT zu schreiben und zu debuggen, und hilft Ihnen auch, es zu verstehen, wenn Sie es in X Monaten (oder Jahren) noch einmal aufrufen müssen.
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

Beachten Sie die unterschiedlichen Einrückungsebenen. Beispielsweise wird tee von samtools leicht eingerückt, dann werden die Argumente von tee von tee eingerückt und dann ist das Ende wieder auf derselben Einrückungsebene wie tee. Dies alles hilft zu verstehen, welche Argumente zu welchem ​​Programm gehören und wo in der Pipeline (oder Schleife usw.) Sie sich beim Lesen befinden.

Übrigens sind Backslashes zum Fortsetzen einer Zeile nach einem Pipe-Zeichen optional.

oder auch:

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

verwandte Informationen