在 snakemake 中合并 shell 个命令行

Combine shell command lines in snakemake

我想将两个命令行合并为一个命令行以避免中间文件。

workdir: "/path/to/workdir/"

rule all:
    input: 
        "my.filtered.vcf.gz"

rule bedtools:
    input:
        invcf="/path/to/my.vcf.gz",
        bedgz="/path/to/my.bed.gz"
    output:
        outvcf="my.filtered.vcf.gz"
    shell:
        "/Tools/bedtools2/bin/bedtools intersect -a {input.invcf} -b {input.bedgz} -header -wa |"
        "/Tools/bcftools/bcftools annotate -c CHROM,FROM,TO,GENE -h <(echo '##INFO=<ID=GENE,Number=1,Type=String,Description="Gene name">') > {output.outvcf}"

我收到无效的语法错误。如果您能解释如何在 snakemake 中组合多个 shell 行,我将不胜感激。

由于您在此处的 shell 中使用的 ",您可能得到了无效的语法:Description="Gene name">。这将关闭您的 shell。您可以转义这些引号或使用 """ 语法:

rule bedtools:
    input:
        invcf="/path/to/my.vcf.gz",
        bedgz="/path/to/my.bed.gz"
    output:
        outvcf="my.filtered.vcf.gz"
    shell:
        "/Tools/bedtools2/bin/bedtools intersect -a {input.invcf} -b {input.bedgz} -header -wa |"
        "/Tools/bcftools/bcftools annotate -c CHROM,FROM,TO,GENE -h <(echo '##INFO=<ID=GENE,Number=1,Type=String,Description=\"Gene name\">') > {output.outvcf}"

rule bedtools:
    input:
        invcf="/path/to/my.vcf.gz",
        bedgz="/path/to/my.bed.gz"
    output:
        outvcf="my.filtered.vcf.gz"
    shell:
        """
        /Tools/bedtools2/bin/bedtools intersect -a {input.invcf} -b {input.bedgz} -header -wa | /Tools/bcftools/bcftools annotate -c CHROM,FROM,TO,GENE -h <(echo '##INFO=<ID=GENE,Number=1,Type=String,Description="Gene name">') > {output.outvcf}
        """

请注意,您可以在 """ 中使用多行。没有管道的例子:

shell:
    """
    bedtools .... {input} > tempFile 
    bcftools .... tempFile > tempFile2
    whatever .... tempFile2 > {output}
    """

转义双引号是个问题,但要在格式和管道上多加一点。

我更喜欢在 " 中换行的语法,这样行可以 spaced 更好:

rule bedtools:
    input:
        invcf="/path/to/my.vcf.gz",
        bedgz="/path/to/my.bed.gz"
    output:
        outvcf="my.filtered.vcf.gz"
    shell:
        "/Tools/bedtools2/bin/bedtools "
           "intersect "
           "-a {input.invcf} "
           "-b {input.bedgz} "
           "-header -wa "
        "| /Tools/bcftools/bcftools "
           "annotate "
           "-c CHROM,FROM,TO,GENE "
           "-h <(echo '##INFO=<ID=GENE,Number=1,Type=String,Description=\"Gene name\">') "
        "> {output.outvcf}"

我发现通过四处移动线条可以更清楚地看到每个参数并且更容易更改。但请注意,每行的结尾 space 是必需的,如果您需要单独的命令,则必须使用显式换行符 \n。打印提示时,输出的格式很好。使用 """ 语法,您必须在末尾使用 \ 转义每个换行符,并在打印时保留行首的 spaces。

如果您有很多管道工作要做,请查看 pipe flag。你把第一步写成规则,snakemake 在规则之间生成一个命名管道,将它们作为一个组提交:

rule bedtools_intersect:
    input:
        invcf="/path/to/my.vcf.gz",
        bedgz="/path/to/my.bed.gz"
    output:
        outvcf=pipe("my.intersected.vcf.gz")
    shell:
        "/Tools/bedtools2/bin/bedtools "
           "intersect "
           "-a {input.invcf} "
           "-b {input.bedgz} "
           "-header -wa "
        "> {output.outvcf}"

rule bcftools_annotate:
    input:
        invcf="my.intersected.vcf.gz"
    output:
        outvcf="my.filtered.vcf.gz"
    shell:
        "/Tools/bcftools/bcftools "
           "annotate "
           "-c CHROM,FROM,TO,GENE "
           "-h <(echo '##INFO=<ID=GENE,Number=1,Type=String,Description=\"Gene name\">') "
           "{input.invcf} "
        "> {output.outvcf}"

优点是您可以在整个管道中重复使用每条规则进行交叉或注释,同时避免临时文件。