tee in for loop não funciona como esperado

tee in for loop não funciona como esperado

Estou tentando usar teeem um loop for como tal:

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;

Ou seja, usando a saída de samtools mpileupe canalizando isso em dois comandos separados. Eu adicionei o tail -n 5para evitar que a saída de samtools mpileupseja impressa em sua totalidade no stdout (no entanto, quero que a saída completa seja usada como entrada java -jar varscan).

Isso parece funcionar inicialmente, mas o comando parece não ser concluído (o tamanho do arquivo para cada saída é menor do que se o comando fosse executado sem tee).

Eventualmente, recebo um erro informando que os dois java -jar $varscancomandos estão aguardando uma entrada que nunca chega (antes de ter a chance de iniciar a segunda iteração do loop).

Esta é a melhor maneira de realizar o que procuro, ou seja, usar a saída do primeiro comando em dois comandos separados (de preferência, sem gravar/imprimir a saída do primeiro comando)? É teeincompatível com loops for?

Desde já, obrigado.

Responder1

  1. cite suas variáveis
  2. não analise ls
  3. opcional, mas recomendado: simplifique seu script enão se repita. Você gera o nome base duas vezes com sed e acrescenta um sufixo diferente a cada vez - seria melhor gerá-lo uma vez - isso reduziria o risco de bugs e melhoraria a legibilidade (e melhoraria um pouco o desempenho - é "mais barato" fazer algo uma vez e reutilizar o resultado do que fazer exatamente a mesma operação duas ou mais vezes).
  4. legibilidade (ou seja, a capacidade de ler eentenderum programa que você escreveu) é um dos, se nãooas coisas mais importantes ao escrever código....então, sempre que o desempenho não for absolutamente crítico, é melhor priorizar a escrita do seu código de uma forma que o torne mais fácil de entender. Isso pode significar inserir mais quebras de linha ou recuos, ou dividir comandos longos e complicados em comandos mais curtos e mais simples. Isso ajudará a escrever e depurar o script AGORA e também ajudará você a entendê-lo quando precisar revisitá-lo em X meses (ou anos).
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

Observe os vários níveis de recuo. por exemplo, tee é ligeiramente recuado de samtools, então os argumentos de tee são recuados de tee, e então a cauda volta ao mesmo nível de indentação de tee. Tudo isso ajuda a entender quais argumentos pertencem a qual programa e onde você está no pipeline (ou loop, etc.) enquanto o lê.

Aliás, barras invertidas para continuar uma linha são opcionais após uma barra vertical.

ou mesmo:

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

informação relacionada