와일드카드로 규칙 일반화하기

챕터 6에서 보았 듯이, 입력과 출력 사이에 반복되는 부분 문자열이 있는 경우 이를 와일드카드(wildcards)로 추출할 수 있습니다. 이를 통해 특정 입력에서 특정 출력을 만드는 규칙을 패턴과 일치하는 모든 입력/출력 세트에 작동하는 규칙으로 바꿀 수 있습니다.

예를 들어, 다음 코드는 특정 게놈에서 하나의 sourmash 스케치를 생성합니다.

rule sketch_genomes_1:
    input:
        "genomes/GCF_000017325.1.fna.gz",
    output:
        "GCF_000017325.1.fna.gz.sig",
    shell: """
        sourmash sketch dna -p k=31 {input} --name-from-first
    """

반면, 아래 규칙은 .fna.gz로 끝나는 어떤 게놈에 대해서도 동일한 작업을 수행합니다!

rule sketch_genomes_1:
    input:
        "genomes/{accession}.fna.gz",
    output:
        "{accession}.fna.gz.sig",
    shell: """
        sourmash sketch dna -p k=31 {input} \
            --name-from-first
    """

여기서 {accession}genomes/ 디렉토리 아래에 있고 .fna.gz로 끝나는 모든 파일 이름에 대해 필요에 따라 “빈칸을 채우는” 와일드카드입니다.

Snakemake는 단순한 패턴 매칭을 사용하여 {accession} 값을 결정합니다. .fna.gz.sig로 끝나는 파일 이름이 요청되면, Snakemake는 접두사를 가져와 일치하는 입력 파일 genomes/{accession}.fna.gz를 찾고 그에 따라 {input}을 채웁니다.

와일드카드는 믿을 수 없을 정도로 유용하며, 이를 사용하면 하나의 규칙으로 수백 또는 수천 개의 파일을 생성할 수 있는 경우가 많습니다! 하지만 고려해야 할 몇 가지 미묘한 부분들이 있습니다. 이 장에서는 가장 중요한 미묘한 부분들을 다루고 자세한 내용을 배울 수 있는 링크를 제공하겠습니다.

와일드카드 기본 규칙

먼저 와일드카드의 몇 가지 기본 규칙을 살펴보겠습니다.

와일드카드는 원하는 출력에 의해 결정됩니다

와일드카드의 가장 중요하고 첫 번째 규칙은 이것입니다. Snakemake는 생성하도록 요청받은 파일 이름을 기반으로 와일드카드 값을 채웁니다.

다음 규칙을 고려해 보세요.

# targets: result1.a.out

rule a:
    output: "{prefix}.a.out"
    shell: "touch {output}"

출력 블록의 와일드카드는 .a.out으로 끝나는 어떤 파일과도 일치하며, 관련 셸 명령어가 해당 파일을 생성할 것입니다! 이것은 강력하면서도 동시에 제약이기도 합니다. .a.out 접미사가 붙은 모든 파일을 생성할 수 있지만, 동시에 파일 생성을 요청해야 하기 때문입니다.

즉, 이 규칙을 활용하려면 .a.out으로 끝나는 파일을 필수 입력으로 갖는 또 다른 규칙이 있어야 합니다. (명령줄에서 해당 파일을 명시적으로 요청할 수도 있습니다.) Snakemake가 와일드카드 값을 추측할 다른 방법은 없습니다. Snakemake는 명시적인 것이 암시적인 것보다 낫다는 원칙을 따르며, 사용자가 어떤 파일을 생성하고 싶은지 추측하지 않습니다.

예를 들어, 위의 규칙은 하나 이상의 .a.out 파일을 요청하는 다른 규칙과 짝을 이룰 수 있습니다.

rule make_me_a_file:
    input:
        "result1.a.out",
        "result2.a.out",

또한 규칙에 와일드카드를 넣으면 더 이상 규칙 이름으로 해당 규칙을 실행할 수 없다는 뜻이기도 합니다. 대신 파일 이름을 요청해야 합니다. 와일드카드가 포함된 규칙을 실행하려 하면서 어떤 파일 이름을 생성하고 싶은지 알려주지 않으면 다음과 같은 오류가 발생합니다.

Target rules may not contain wildcards.

와일드카드 규칙을 사용하는 흔한 방법 중 하나는 expand를 사용하여 원하는 파일 목록을 구성하는 다른 규칙을 두는 것입니다. 이는 종종 와일드카드 목록을 불러오는 glob_wildcards와 함께 사용됩니다. 아래의 접두사 기반 파일 이름 변경 레시피나 파일 이름 생성을 위한 expand 사용 장을 참고하세요.

규칙에서 사용된 모든 와일드카드는 output: 블록의 와일드카드와 일치해야 합니다

Snakemake는 규칙의 다른 부분에 있는 와일드카드를 채우기 위해 output: 블록의 와일드카드를 사용하므로, 하나 이상의 출력에 언급된 와일드카드만 사용할 수 있습니다.

이는 input: 블록에서 사용되는 모든 와일드카드가 output:에도 있어야 함을 의미합니다. 입력 블록에는 analysis 와일드카드가 포함되어 있지만 출력 블록에는 사용되지 않는 다음 예시를 보십시오.

# 이 코드는 작동하지 않습니다:

rule analyze_sample:
   input: "{sample}.x.{analysis}.in"
   output: "{sample}.out"

이것이 작동하지 않는 이유는 Snakemake가 입력 블록의 analysis 와일드카드를 어떻게 채워야 할지 모르기 때문이며, 다음과 같은 오류가 발생합니다.

WildcardError in line 1 of ...
Wildcards in input files cannot be determined from output files:
'analysis'

이렇게 생각해 보세요. 만약 이것이 작동한다면, 동일한 출력에 대해 여러 개의 다른 입력 파일이 존재할 수 있게 되고, Snakemake는 원하는 출력을 생성하기 위해 어떤 입력 파일을 사용해야 할지 선택할 방법이 없게 됩니다. 또한 사용된 입력에 따라 출력이 달라질 수 있어 재현성 문제로 이어질 수 있습니다.

input: 블록의 모든 와일드카드는 output: 블록에 있어야 합니다. 하지만 output: 블록의 와일드카드가 input: 블록에 있을 필요가 없는 상황도 있습니다. 셸 블록의 파라미터를 결정하기 위해 와일드카드를 사용하는 방법에 대해서는 아래의 “셸 블록에서 사용할 파라미터를 결정하기 위한 와일드카드 사용” 섹션을 참고하세요!

와일드카드는 각 규칙 내에서만 유효합니다

와일드카드 이름은 규칙 블록 내에서만 일치하면 됩니다. 와일드카드는 규칙 간에 공유되지 않습니다. 일관성과 가독성을 위해 여러 규칙에서 동일한 와일드카드 이름을 사용할 있지만, Snakemake는 이를 독립적인 와일드카드로 취급하며 와일드카드 값이 공유되지 않습니다.

예를 들어, 아래 두 규칙은 모두 와일드카드 a를 사용합니다.

rule analyze_this:
    input: "{a}.first.txt"
    output: "{a}.second.txt"

rule analyze_that:
    input: "{a}.second.txt"
    output: "{a}.third.txt"

하지만 이것은 별개의 규칙에서 서로 다른 와일드카드 ab를 사용하는 다음 두 규칙과 동일합니다.

rule analyze_this:
    input: "{a}.first.txt"
    output: "{a}.second.txt"

rule analyze_that:
    input: "{b}.second.txt"
    #        ^-- 첫 번째 규칙의 'a' 대신 'b' 사용
    output: "{b}.third.txt"
    #        ^-- 첫 번째 규칙의 'a' 대신 'b' 사용

와일드카드가 독립적이라는 규칙에는 한 가지 예외가 있습니다. 전역 와일드카드 제약(global wildcard constraints)을 사용하여 와일드카드 이름별로 매칭을 제한하는 경우, 해당 제약 조건은 Snakefile 내에서 해당 와일드카드 이름이 사용되는 모든 곳에 적용됩니다. 하지만 와일드카드 은 여전히 독립적입니다. 단지 동일한 이름의 모든 와일드카드가 제약 조건을 공유할 뿐입니다.

와일드카드 값은 독립적이므로 모든 규칙에서 서로 다른 와일드카드를 쓸 수도 있지만, Snakefile 전체에서 동일한 의미를 갖도록 와일드카드를 선택하는 것이 좋은 관례입니다. 예를 들어 샘플 식별자에는 항상 일관되게 sample을 사용하고 데이터베이스 ID에는 accession을 사용하는 식입니다. 이렇게 하면 Snakefile을 읽기가 훨씬 쉬워집니다!

한 가지 흥미로운 부연 설명: 와일드카드는 각 규칙 내에서만 유효하기 때문에, 서로 다른 규칙에서 패턴의 서로 다른 부분을 매칭할 수도 있습니다! 아래의 “와일드카드 조합 및 매칭” 섹션을 참고하세요.

와일드카드 네임스페이스는 input:output: 블록에서는 암시적으로 사용 가능하지만, 다른 블록에서는 그렇지 않습니다.

규칙 내의 input:output: 블록에서는 와일드카드를 이름으로 직접 참조할 수 있습니다. 규칙의 다른 대부분의 부분에서 와일드카드를 사용하려면 wildcards 접두사를 사용해야 합니다. 이 규칙의 유일한 예외는 params: 블록입니다 (params: 블록과 {params} 장 참고). 여기서 wildcards네임스페이스(namespace)이며, 이에 대해서는 나중에 더 자세히 이야기하겠습니다.

다음 Snakefile을 고려해 보세요.

# 이 코드는 작동하지 않습니다:

rule analyze_this:
    input: "{a}.first.txt"
    output: "{a}.second.txt"
    shell: "analyze {input} -o {output} --title {a}"

여기서 다음과 같은 오류가 발생합니다.

NameError: The name 'a' is unknown in this context. Did you mean 'wildcards.a'?

오류 메시지에서 제안하듯이 셸 블록에서는 대신 wildcards.a를 사용해야 합니다.

rule analyze_this:
    input: "{a}.first.txt"
    output: "{a}.second.txt"
    shell: "analyze {input} -o {output} --title {wildcards.a}"

와일드카드는 별도의 제약이 없는 한 가능한 한 넓게 매칭됩니다

와일드카드 패턴 매칭은 가장 긴 가능성을 선택하므로 때로는 약간 혼란스러운 동작을 보일 수 있습니다. 다음을 고려해 보세요.

rule all:
    input:
        "x.y.z.gz"

rule something:
    input: "{prefix}.{suffix}.txt"
    output: "{prefix}.{suffix}.gz"
    shell: "gzip -c {input} > {output}"

something 규칙에서 원하는 출력 파일 x.y.z.gz에 대해, {prefix}는 현재 x.y가 되고 {suffix}z가 됩니다. 하지만 {prefix}x이고 suffixy.z가 되는 것도 똑같이 유효할 수 있습니다.

더 극단적인 예시는 탐욕적 매칭(greedy matching)을 더 명확하게 보여줍니다.

rule all:
    input:
        "longer_filename.gz"

rule something:
    input: "{prefix}{suffix}.txt"
    output: "{prefix}{suffix}.gz"
    shell: "gzip -c {input} > {output}"

여기서 {suffix}는 단일 문자 e로 줄어들고, {prefix}longer_filenam이 됩니다!

와일드카드 매칭의 두 가지 간단한 규칙은 다음과 같습니다. * 모든 와일드카드는 최소 한 글자 이상과 일치해야 합니다. * 그 후, 와일드카드는 탐욕적으로 매칭됩니다. 각 와일드카드는 다음 와일드카드가 고려되기 전에 가능한 모든 것을 매칭합니다.

이것이 와일드카드 매칭을 제한하기 위해 와일드카드 제약을 사용하는 것이 좋은 이유입니다. 아래의 “서브디렉토리 및/또는 마침표를 방지하기 위한 와일드카드 제한”에서 몇 가지 예시를 확인하고, 자세한 내용은 와일드카드 제약 장을 참고하세요!

와일드카드 예시

여러 파일에서 하나의 규칙 실행하기

와일드카드를 사용하여 동일하고 간단한 규칙을 많은 파일에 실행할 수 있습니다. 이는 Snakemake의 가장 간단하면서도 강력한 용도 중 하나입니다!

많은 파일을 압축하기 위한 다음 Snakefile을 고려해 보세요.

rule all:
    input:
        "compressed/F3D141_S207_L001_R1_001.fastq.gz",
        "compressed/F3D141_S207_L001_R2_001.fastq.gz",
        "compressed/F3D142_S208_L001_R1_001.fastq.gz",
        "compressed/F3D142_S208_L001_R2_001.fastq.gz"

rule gzip_file:
    input:
        "original/{filename}"
    output:
        "compressed/{filename}.gz"
    shell:
        "gzip -c {input} > {output}"

이 Snakefile은 생성하려는 압축 파일 목록을 지정하고, 입력 파일을 찾고 셸 블록을 채우는 데 필요한 패턴 매칭을 와일드카드에 의존합니다.

이 강력한 패턴에 대한 더 많은 예시는 for 루프를 Snakefile로 대체하기를 참고하세요!

하지만 이 Snakefile은 작성하기 불편하고 실수할 가능성이 있습니다.

  • 파일이 많을 경우 일일이 나열하는 것은 번거롭습니다!
  • 파일 목록을 생성하기 위해 일일이 이름을 바꿔야 하는데, 이 과정에서 실수가 생길 수 있습니다!

Snakemake는 이러한 문제를 도와줄 몇 가지 기능을 제공합니다. 텍스트 파일이나 스프레드시트에서 파일 목록을 로드하거나, glob_wildcards를 사용하여 디렉토리에서 직접 목록을 가져올 수 있습니다. 또한 expand를 사용하여 일괄적으로 이름을 바꿀 수도 있습니다. 아래 예시들을 계속해서 읽어보세요!

Note왜 이것이 gzip을 직접 사용하는 것보다 나은가요?

gzip -k original/* 명령을 사용하고 파일을 최종 위치로 이동시켜서 동일한 작업을 수행할 수도 있습니다.

gzip -k original/*을 사용하는 것과 Snakemake를 사용하는 것이 어떻게 다를까요? 그리고 더 나은가요?

첫째, 결과는 다르지 않습니다. 두 방식 모두 입력 파일 세트를 압축하며, 그것이 여러분이 원하는 결과입니다! 하지만 gzip -k 명령은 순차적으로 실행되며 병렬로 실행되지 않습니다. 즉, gzip은 기본적으로 한 번에 하나의 파일만 압축합니다. 반면 Snakefile은 gzip_file 규칙을 -j로 지정한 만큼의 프로세서를 사용하여 병렬로 실행합니다. 생물정보학에서 흔히 겪는 수많은 파일을 처리해야 하는 문제라면, Snakemake 버전이 잠재적으로 훨씬 더 빠르게 실행될 수 있습니다.

둘째, 명령줄에서 gzip -k original/*로 많은 파일을 지정하는 것은 gzip에서는 작동하지만 모든 셸 명령어에서 다 작동하는 것은 아닙니다. 어떤 명령어는 한 번에 하나의 파일만 처리할 수 있습니다. gzip은 다행히 하나 이상의 파일을 주어도 잘 작동할 뿐입니다. 다른 많은 프로그램(예: FASTQ 파일 전처리를 위한 fastp 프로그램)은 한 번에 하나의 데이터셋에서만 실행됩니다. (Snakemake가 커스텀 명령줄을 유연하게 작성하는 방법을 제공한다는 점도 언급할 가치가 있습니다. 예시는 입력 및 출력 블록 장을 참고하세요.)

셋째, Snakefile에서는 규칙 실행 후 존재할 것으로 예상되는 파일을 명시적으로 지정하고 있습니다. 반면 셸에서 gzip -k original/*을 실행하면 original/에 있는 모든 파일을 압축하라고 요청하는 것입니다. 실수로 original 하위 디렉토리의 파일을 삭제했다면, gzip은 이를 알지 못하고 불평도 하지 않겠지만 Snakemake는 알려줄 것입니다. 이것은 반복해서 강조될 주제로, 예상되는 파일을 명확하게 지정하는 것이 가능한 실수를 경고받을 수 있어 종종 더 안전합니다.

넷째, Snakefile 방식은 출력 파일의 이름을 흥미로운 방식으로 변경할 수 있게 해줍니다. gzip -k original/*를 사용하면 원래 파일 이름에 묶이게 됩니다. 이 기능은 다음 섹션에서 살펴보겠습니다!

glob_wildcards를 사용하여 접두사로 파일 이름 변경하기

original/ 하위 디렉토리에 다음과 같이 이름이 지정된 파일 세트가 있다고 가정해 봅시다.

F3D141_S207_L001_R1_001.fastq
F3D141_S207_L001_R2_001.fastq

이제 .fastq 앞의 _001 접미사를 제거하여 이름을 모두 변경하고 싶다고 가정해 보겠습니다. 와일드카드를 사용하면 매우 간단합니다!

아래 Snakefile은 glob_wildcards를 사용하여 디렉토리에서 파일 목록을 로드한 다음, renamed/ 하위 디렉토리에 새 이름으로 복사본을 만듭니다. 여기서 glob_wildcards는 디렉토리의 사용 가능한 파일 세트에서 {sample} 패턴을 추출합니다.

# 먼저, 이 형식의 파일 이름과 일치하는 항목을 찾습니다.
files = glob_wildcards("original/{sample}_001.fastq")

# 다음으로, 원하는 이름의 형식을 지정합니다.
rule all:
    input:
        expand("renamed/{sample}.fastq", sample=files.sample)

# 마지막으로, 입력에서 출력으로 이동하는 레시피를 snakemake에 제공합니다.
rule rename:
    input:
        "original/{sample}_001.fastq",
    output:
        "renamed/{sample}.fastq"
    shell:
        "cp {input} {output}"

이 Snakefile은 또한 로드된 목록을 원하는 파일 이름 세트로 다시 작성하기 위해 expand를 활용합니다. 이는 더 이상 파일 목록을 직접 일일이 쓸 필요 없이 Snakemake에게 맡길 수 있음을 의미합니다! expand에 대해서는 파일 이름 생성을 위한 expand 사용에서 자세히 다룹니다.

여기서 cp 대신 mv를 사용할 수도 있는데, 그렇게 하면 glob_wildcards는 실행 후 변경된 파일을 더 이상 감지하지 못하게 됩니다.

이 Snakefile은 디렉토리 자체에서 파일 목록을 로드하므로, 실수로 입력 파일을 삭제하더라도 Snakemake가 불평하지 않을 것입니다. 파일 이름을 변경할 때는 이것이 문제를 일으킬 가능성이 낮지만, 워크플로를 실행할 때는 문제를 피하기 위해 텍스트 파일이나 스프레드시트에서 샘플 목록을 로드하는 것을 권장합니다.

또한 이 Snakefile은 original/뿐만 아니라 모든 하위 디렉토리의 파일도 찾아 이름을 변경합니다! 이는 glob_wildcards가 기본적으로 모든 하위 디렉토리를 포함하기 때문입니다. 하위 디렉토리에서 로드하는 것을 방지하기 위해 와일드카드 제약을 사용하는 방법은 다음 섹션을 확인하세요.

서브디렉토리 및/또는 마침표를 방지하기 위한 와일드카드 제한

와일드카드는 ‘/’를 포함한 모든 문자열과 일치하므로, glob_wildcards는 자동으로 하위 디렉토리의 파일을 찾고 파일 이름의’.’ 이나 ‘-’ 같은 일반적인 구분 기호와도 일치하도록 “확장”됩니다. 이를 흔히 “탐욕적 매칭”이라고 하며, 때때로 와일드카드가 원하는 것보다 훨씬 더 많은 파일 이름과 일치하게 된다는 것을 의미합니다! 와일드카드 제약을 사용하여 와일드카드 매칭을 제한할 수 있습니다.

아래에는 두 가지 일반적인 와일드카드 제약 조건이 개발 및 조합되어 있습니다. 첫 번째 제약 조건은 하위 디렉토리의 파일을 피하고, 두 번째 제약 조건은 마침표를 피합니다.

# ANCHOR: 제약 조건
# 모든 .txt 파일 일치 - 제약 조건 없음
all_files = glob_wildcards("{filename}.txt").filename

# 이 디렉터리의 모든 .txt 파일만 일치 - / 방지
this_dir_files = glob_wildcards("{filename,[^/]+}.txt").filename

# 이름에 마침표가 하나만 있는 모든 파일 일치 - . 방지
prefix_only = glob_wildcards("{filename,[^.]+}.txt").filename

# 이 디렉터리에서 이름에 마침표가 하나만 있는 모든 파일 일치
# / 및 . 방지
prefix_and_dir_only = glob_wildcards("{filename,[^./]+}.txt").filename
# ANCHOR_END: 제약 조건

print(all_files)
print(this_dir_files)
print(prefix_only)
print(prefix_and_dir_only)

assert set(all_files) == { 'file1.subset', 'file1', 'subdir/file2', 'subdir/file2.subset', 'subdir/nested/file3' }
assert set(this_dir_files) == { 'file1.subset', 'file1' }
assert set(prefix_only) == { 'file1', 'subdir/file2', 'subdir/nested/file3' }
assert prefix_and_dir_only == ['file1']

자세한 내용은 와일드카드 제약을 참고하세요.

고급 와일드카드 예시

여러 와일드카드를 사용한 파일 이름 변경

위의 첫 번째 파일 이름 변경 예시는 파일의 접미사만 변경하고 단일 와일드카드를 사용할 수 있을 때 매우 잘 작동하지만, 더 복잡한 이름 변경을 원할 경우 여러 개의 와일드카드를 사용해야 할 수도 있습니다.

F3D141_S207_L001_R1_001.fastq 형식의 파일 이름을 F3D141_S207_R1.fastq로 변경하고 싶은 상황을 가정해 보겠습니다. 안타깝게도 단일 와일드카드로는 불가능하지만, 다음과 같이 두 개를 사용할 수 있습니다.

# 먼저, 이 형식의 파일 이름과 일치하는 항목을 찾습니다.
files = glob_wildcards("original/{sample}_L001_{r}_001.fastq")

# 다음으로, 원하는 이름의 형식을 지정합니다.
rule all:
    input:
        expand("renamed/{sample}_{r}.fastq", zip,
               sample=files.sample, r=files.r)

# 마지막으로, 입력에서 출력으로 이동하는 레시피를 snakemake에 제공합니다.
rule rename:
    input:
        "original/{sample}_L001_{r}_001.fastq",
    output:
        "renamed/{sample}_{r}.fastq"
    shell:
        "cp {input} {output}"

이 코드에서 세 가지 새로운 기능을 사용하고 있습니다.

첫째, glob_wildcards가 여러 와일드카드를 매칭하고 결과 값을 하나의 결과 변수(여기서는 files)에 넣습니다.

둘째, 매칭된 값들이 files.samplefiles.r이라는 두 개의 정렬된 리스트에 배치되어 파일 이름에서 추출된 값들이 쌍으로 일치하게 됩니다.

셋째, expand를 사용할 때 기본값인 product로 가능한 모든 조합을 만드는 대신, zip을 사용하여 두 와일드카드 리스트를 함께 묶도록 요청합니다. zipproduct에 대한 자세한 내용은 파일 이름 생성을 위한 expand 사용을 참고하세요.

또한 이전 예시와 마찬가지로, 이 Snakefile은 original/뿐만 아니라 모든 하위 디렉토리의 파일을 찾아 이름을 변경합니다!

링크: * product 대신 zip을 사용하는 방법에 대한 snakemake 문서

문자열 조합 및 매칭

와일드카드가 규칙에 국한된다는 점의 다소 비직관적이지만 매우 유용한 결과 중 하나는, 범용 규칙과 특정 규칙을 영리한 문자열 매칭을 통해 조합할 수 있다는 것입니다.

여러 샘플의 리드를 여러 참조 게놈에 매핑하고(규칙 map_reads_to_reference), SAM을 BAM 파일로 변환하는 다음 Snakefile을 고려해 보세요.

rule all:
    input:
        "sample1.x.ecoli.bam",
        "sample2.x.shewanella.bam",
        "sample1.x.shewanella.bam"

rule map_reads_to_reference:
    input:
        reads="{sample}.fq",
        reference="{genome}.fa",
    output:
        "{reads}.x.{reference}.sam"
    shell: "minimap2 -ax sr {input.reference} {input.reads} > {output}"
        
rule convert_sam_to_bam:
    input:
        "{filename}.sam"
    output:
        "{filename}.bam"
    shell: "samtools view -b {input} -o {output}"

여기서 Snakemake는 각 규칙에서 서로 다른 와일드카드를 즐겁게 사용하고 패턴의 서로 다른 부분에 매칭시키고 있습니다!

  • 규칙 convert_sam_to_bam.bam.sam 접미사만을 기반으로 모든 SAM 파일을 BAM 파일로 범용적으로 변환합니다.

  • 하지만 map_reads_to_references{sample}.x.{reference} 패턴과 일치하는 매핑 파일만 생성하며, 이는 다시 {reference}.fa{sample}.fastq의 존재 여부에 따라 달라집니다.

이것이 가능한 이유는 궁극적으로 Snakemake가 단지 문자열을 매칭할 뿐이며 매칭하는 문자열의 구조에 대해 아무것도 “알지” 못하기 때문입니다. 또한 규칙 간에 와일드카드를 기억하지도 않습니다. 따라서 Snakemake는 한 규칙에서 한 세트의 와일드카드를 매칭시키고, 다른 규칙에서 다른 세트의 와일드카드를 매칭시키는 일을 기꺼이 수행합니다!

셸 블록에서 사용할 파라미터를 결정하기 위한 와일드카드 사용

와일드카드를 사용하여 규칙을 작성할 수도 있는데, 여기서 내용을 생생하기 위해 사용되는 파라미터가 파일 이름을 기반으로 결정되는 방식입니다. 예를 들어 FASTQ 파일의 서브셋을 생성하는 다음 예시를 보십시오.

rule all:
    input:
        "big.subset100.fastq"

rule subset:
    input:
        "big.fastq"
    output:
        "big.subset{num_lines}.fastq"
    shell: """
        head -{wildcards.num_lines} {input} > {output}
    """

여기서 와일드카드는 입력 파일 이름이 아닌 출력 파일 이름에만 있습니다. 와일드카드 값은 Snakemake가 파일에서 선택할 head의 줄 수를 채우는 데 사용됩니다!

이는 셸 명령어에 다양한 파라미터를 제공하여 파일을 생성할 때 매우 유용할 수 있습니다. 저희는 이를 “파라미터 스윕(parameter sweeps)”이라고 부릅니다. 이에 대해서는 나중에 더 자세히 다루겠습니다!

와일드카드에 대한 생각

와일드카드(expandglob_wildcards와 함께)는 Snakemake에서 가장 강력하고 유용한 기능 중 하나입니다. 단순한 패턴에 전적으로 기반하여 임의의 수의 파일에 규칙을 범용적으로 적용할 수 있게 해줍니다.

하지만 그 강력함 뒤에는 꽤 많은 복잡성이 따릅니다!

궁극적으로 와일드카드는 모두 문자열패턴에 관한 것입니다. Snakemake는 패턴 매칭을 사용하여 원하는 출력 파일에서 패턴을 추출한 다음, 규칙의 다른 곳에 해당 매칭 결과를 채워 넣습니다. 그 과정에서 발생하는 대부분의 복잡성은 패턴 매칭 및 채우기에서의 모호함을 피하는 것과, 실제로 생성하려는 모든 파일의 이름을 구성하는 과제에서 비롯됩니다.

추가 참고 자료

참고: 와일드카드에 관한 Snakemake 문서