Obsidian 작업을 형식 간에 변환하기
Obsidian Tasks에는 보관함을 한 형식에서 다른 형식으로 다시 써 주는 명령이 없습니다. 플러그인 문서에도 그렇게 적혀 있습니다. 아래 변환은 그 일을 하는 스크립트와 레시피이며, 모두 플러그인 자체 문서의 예시 줄로 검증했습니다. 여기에 도구가 존재하는 유일한 변환, 즉 작업 줄에서 작업 파일로, 그리고 그 반대로의 변환도 다룹니다.
2026년 10월에 Obsidian Tasks 8.6, Task Genius 9.13, TaskNotes 4.14 기준으로 작성했습니다. 필드 이름과 기호는 치트시트에 있습니다.
무엇이든 바꾸기 전에
- 보관함 백업하기. 폴더를 복사하거나 git에 커밋하세요. 4,000줄을 다시 쓰는 스크립트는 되돌리기 쉬워야 합니다.
- 먼저 복사본에서 작업하기. 보관함 복사본에서 변환을 실행하고 Obsidian으로 연 다음, 평소 쓰는 작업 쿼리 하나를 실행하세요. 개수를 원본과 비교합니다.
- 변환한 뒤 플러그인 전환하기. Obsidian Tasks는 한 번에 한 형식만 읽습니다. 먼저 줄을 변환한 뒤 설정에서 작업 형식을 바꾸면 플러그인이 변환이 덜 된 보관함을 보는 일이 없습니다.
- 남은 것 확인하기. 옛 기호(이모지는 📅, ⏳, ⏫, Dataview는 due::, repeat::)를 보관함에서 검색해 레시피가 건너뛴 줄을 찾으세요.
어떤 변환이 필요한가
| 변환 전 | 변환 후 | 방법 |
|---|---|---|
| 이모지 줄 | Dataview 필드 | 아래의 스크립트 또는 찾아 바꾸기 레시피. |
| Dataview 필드 | 이모지 줄 | 아래의 역방향 스크립트 또는 레시피. |
| 둘 중 아무거나 | Task Genius | 다시 쓸 것이 없습니다. Task Genius는 같은 줄의 둘을 모두 읽습니다. 어느 쪽으로 쓸지는 설정에서 고릅니다. |
| 작업 줄 | 작업 파일 | TaskNotes는 한 번에 한 줄씩 변환합니다. TaskForge 명령줄은 여러 개를 한꺼번에 변환합니다. |
| 작업 파일 | 작업 줄 | TaskForge 명령줄. 잃게 될 내용이 있으면 미리 보기로 알려 줍니다. |
이모지에서 Dataview 필드로
각 이모지와 그 값이 대괄호 필드가 됩니다. 우선순위 이모지는 단어 값을 가진 priority 필드가 되고, 반복 텍스트는 괄호 안으로 들어갑니다. 치환은 이 순서대로 실행하세요. 날짜와 우선순위를 먼저, 반복을 마지막에 하면 반복 텍스트가 다음 대괄호가 시작되는 곳에서 끝납니다.
변환 전과 후
- [ ] Send invoice to Acme ⏫ 🔁 every month ➕ 2026-10-01 ⏳ 2026-11-01 📅 2026-11-03 #finance
- [x] Book flights 📅 2026-10-25 ✅ 2026-10-20
- [ ] Order parts 🆔 parts1
- [ ] Assemble 🛫 2026-11-10 ⛔ parts1 📅 2026-11-15 - [ ] Send invoice to Acme [priority:: high] [repeat:: every month] [created:: 2026-10-01] [scheduled:: 2026-11-01] [due:: 2026-11-03] #finance
- [x] Book flights [due:: 2026-10-25] [completion:: 2026-10-20]
- [ ] Order parts [id:: parts1]
- [ ] Assemble [start:: 2026-11-10] [dependsOn:: parts1] [due:: 2026-11-15] 필드별 찾아 바꾸기
이 패턴은 VS Code처럼 파일 전체에 걸친 정규식 검색이 되는 편집기에서 동작하며, VS Code에서는 캡처한 텍스트를 $1로 씁니다. 정규식 모드와 대소문자 구분을 켜세요. 스크립트와 달리 체크박스뿐 아니라 모든 줄에 적용됩니다.
| 필드 | 찾기 | 바꿀 내용 |
|---|---|---|
| 📅 | (?:📅|📆|🗓️?)\s*(\d{4}-\d{2}-\d{2}) | [due:: $1] |
| ⏳ | (?:⏳|⌛)\s*(\d{4}-\d{2}-\d{2}) | [scheduled:: $1] |
| 🛫 | 🛫\s*(\d{4}-\d{2}-\d{2}) | [start:: $1] |
| ➕ | ➕\s*(\d{4}-\d{2}-\d{2}) | [created:: $1] |
| ✅ | ✅\s*(\d{4}-\d{2}-\d{2}) | [completion:: $1] |
| ❌ | ❌\s*(\d{4}-\d{2}-\d{2}) | [cancelled:: $1] |
| 🔺 | 🔺️? | [priority:: highest] |
| ⏫ | ⏫️? | [priority:: high] |
| 🔼 | 🔼️? | [priority:: medium] |
| 🔽 | 🔽️? | [priority:: low] |
| ⏬ | ⏬️? | [priority:: lowest] |
| 🏁 | 🏁\s*(keep|delete) | [onCompletion:: $1] |
| 🆔 | 🆔\s*([A-Za-z0-9_-]+) | [id:: $1] |
| ⛔ | ⛔\s*([A-Za-z0-9_-]+(?:\s*,\s*[A-Za-z0-9_-]+)*) | [dependsOn:: $1] |
| 🔁 | 🔁\s*([A-Za-z0-9, !]*[A-Za-z0-9])(?=\s*(?:\[|\^|$)) | [repeat:: $1] |
같은 작업을 스크립트로
emoji_to_dataview.py로 저장한 뒤 python3 emoji_to_dataview.py Inbox.md Projects/*.md를 실행하세요. 체크박스 줄만 건드리고, Obsidian Tasks처럼 각 필드 앞에 공백 두 칸을 쓰며, 대체 마감일과 예정일 기호 📆, 🗓, ⌛도 변환합니다.
#!/usr/bin/env python3
"""Rewrite Obsidian Tasks emoji fields to Dataview [key:: value] fields.
Usage: emoji_to_dataview.py NOTE.md [NOTE.md ...] (rewrites in place; back up first)
Only checkbox lines are touched. Run it on a copy of your vault first.
"""
import os
import re
import sys
DATE = r"(\d{4}-\d{2}-\d{2})"
ID = r"[A-Za-z0-9_-]+"
RULES = [
(rf"(?:📅|📆|🗓️?)\s*{DATE}", r"[due:: \1]"),
(rf"(?:⏳|⌛)\s*{DATE}", r"[scheduled:: \1]"),
(rf"🛫\s*{DATE}", r"[start:: \1]"),
(rf"➕\s*{DATE}", r"[created:: \1]"),
(rf"✅\s*{DATE}", r"[completion:: \1]"),
(rf"❌\s*{DATE}", r"[cancelled:: \1]"),
(r"🔺️?", "[priority:: highest]"),
(r"⏫️?", "[priority:: high]"),
(r"🔼️?", "[priority:: medium]"),
(r"🔽️?", "[priority:: low]"),
(r"⏬️?", "[priority:: lowest]"),
(r"🏁\s*(keep|delete)", r"[onCompletion:: \1]"),
(rf"🆔\s*({ID})", r"[id:: \1]"),
(rf"⛔\s*({ID}(?:\s*,\s*{ID})*)", r"[dependsOn:: \1]"),
# Last, so the rule text ends at the next bracket or the end of the line.
(r"🔁\s*([A-Za-z0-9, !]*[A-Za-z0-9])(?=\s*(?:\[|\^|$))", r"[repeat:: \1]"),
]
TASK = re.compile(r"^(\s*(?:[-*+]|\d+\.)\s+\[.\]\s)(.*)$")
for path in sys.argv[1:]:
out = []
for raw in open(path, encoding="utf-8", newline="").read().split("\n"):
cr = "\r" if raw.endswith("\r") else ""
line = raw[: len(raw) - len(cr)]
m = TASK.match(line)
if m:
head, body = m.groups()
for pattern, repl in RULES:
body = re.sub(pattern, repl, body)
body = re.sub(r"\s*(\[(?:due|scheduled|start|created|completion|cancelled|priority|onCompletion|id|dependsOn|repeat):: )", r" \1", body)
line = head + body
out.append(line + cr)
tmp = path + ".tmp"
with open(tmp, "w", encoding="utf-8", newline="") as fh:
fh.write("\n".join(out))
os.replace(tmp, path)
Dataview 필드에서 이모지로
역방향은 [key:: value]와 (key:: value)를 모두 읽고 표준 이모지를 씁니다. [project:: Website]처럼 모르는 필드는 줄에 그대로 남으며, 숫자로 쓴 우선순위는 플러그인마다 숫자의 의미가 달라 건드리지 않습니다.
- [ ] Send invoice to Acme [priority:: high] [repeat:: every month] [created:: 2026-10-01] [scheduled:: 2026-11-01] [due:: 2026-11-03] #finance
- [x] Book flights [due:: 2026-10-25] [completion:: 2026-10-20]
- [ ] Order parts [id:: parts1]
- [ ] Assemble [start:: 2026-11-10] [dependsOn:: parts1] [due:: 2026-11-15] - [ ] Send invoice to Acme ⏫ 🔁 every month ➕ 2026-10-01 ⏳ 2026-11-01 📅 2026-11-03 #finance
- [x] Book flights 📅 2026-10-25 ✅ 2026-10-20
- [ ] Order parts 🆔 parts1
- [ ] Assemble 🛫 2026-11-10 ⛔ parts1 📅 2026-11-15 앞 스크립트의 출력에 실행하면 위의 예시 줄이 그대로 돌아옵니다. 실제 보관함은 이만큼 깔끔하지 않습니다. 📆, 🗓, ⌛를 쓰던 줄은 📅 또는 ⏳로 돌아오고, 설명이 빈 줄에는 공백이 하나 생깁니다.
dataview_to_emoji.py로 저장한 뒤 같은 방식으로 실행하세요.
#!/usr/bin/env python3
"""Rewrite Dataview [key:: value] task fields to Obsidian Tasks emoji fields.
Usage: dataview_to_emoji.py NOTE.md [NOTE.md ...] (rewrites in place; back up first)
Reads [key:: v] and (key:: v). Only checkbox lines are touched.
"""
import os
import re
import sys
DATE = r"(\d{4}-\d{2}-\d{2})"
ID = r"[A-Za-z0-9_-]+"
def field(key, value):
return rf"[\[(]\s*{key}::\s*{value}\s*[\])]"
RULES = [
(field("due", DATE), r"📅 \1"),
(field("scheduled", DATE), r"⏳ \1"),
(field("start", DATE), r"🛫 \1"),
(field("created", DATE), r"➕ \1"),
(field("completion", DATE), r"✅ \1"),
(field("cancelled", DATE), r"❌ \1"),
(field("priority", "highest"), "🔺"),
(field("priority", "high"), "⏫"),
(field("priority", "medium"), "🔼"),
(field("priority", "low"), "🔽"),
(field("priority", "lowest"), "⏬"),
(field("onCompletion", "(keep|delete)"), r"🏁 \1"),
(field("id", f"({ID})"), r"🆔 \1"),
(field("dependsOn", rf"({ID}(?:\s*,\s*{ID})*)"), r"⛔ \1"),
(field("repeat", r"([A-Za-z0-9, !]*[A-Za-z0-9])"), r"🔁 \1"),
]
TASK = re.compile(r"^(\s*(?:[-*+]|\d+\.)\s+\[.\]\s)(.*)$")
for path in sys.argv[1:]:
out = []
for raw in open(path, encoding="utf-8", newline="").read().split("\n"):
cr = "\r" if raw.endswith("\r") else ""
line = raw[: len(raw) - len(cr)]
m = TASK.match(line)
if m:
head, body = m.groups()
for pattern, repl in RULES:
body = re.sub(pattern, repl, body, flags=re.I if "priority" in pattern else 0)
line = head + re.sub(r"[ \t]{2,}", " ", body).rstrip()
out.append(line + cr)
tmp = path + ".tmp"
with open(tmp, "w", encoding="utf-8", newline="") as fh:
fh.write("\n".join(out))
os.replace(tmp, path)
변환이 처리하지 못하는 것
- 두 필드 사이에 텍스트가 있는 줄. Obsidian Tasks는 줄 끝부터 읽으므로 애초에 그 필드들을 읽지 못했을 것입니다.
- 줄 끝의 ^abc123 같은 블록 링크. 스크립트는 그대로 두며, Obsidian이 기대하는 위치입니다.
- Task Genius 전용 문법: 날짜 뒤의 시각, [#A] 우선순위, 프로젝트와 컨텍스트 필드, iCalendar 반복 규칙. 그런 줄은 그대로 두거나 직접 변환하세요.
- 한 형식이 다르게 표기하는 반복 규칙. 전환 뒤에 특히 when done이 있는 것을 중심으로 몇 가지를 확인하세요.
- 파일 안에 이미 완료된 사본이 있는 반복 작업. 사본은 일반 완료 작업이며 다른 줄처럼 변환됩니다.
- 코드 블록 안의 줄. 스크립트는 줄 단위로 동작하고 펜스를 알지 못하므로 예시를 인용한 노트는 직접 변환하세요.
- [custom:: x] 같은 인식되지 않는 필드가 줄 끝에 남아 있는 경우. Obsidian Tasks는 줄 끝부터 읽으므로 거기서 멈추고, 앞에 있는 변환된 필드는 무시합니다.
- 🔁 규칙 뒤에 #태그가 오는 경우. 반복 규칙이 변환되지 않고 남으므로 태그를 규칙 앞으로 옮기거나 그 줄을 직접 변환하세요.
- 인용 블록이나 콜아웃 안의 작업(> - [ ]로 시작하는 줄). 스크립트는 이런 줄을 건너뜁니다.
- 날짜 뒤의 14:30 같은 시각. 변환된 필드 밖에 그대로 남습니다. Obsidian Tasks에는 시간 필드가 없으므로 읽을 수 있는 것은 Task Genius뿐입니다.
작업 줄에서 작업 파일로
작업 파일은 작업의 필드를 YAML frontmatter에 담은 노트이며, TaskNotes가 쓰는 형식입니다. 줄의 모든 필드가 여기에 자리를 갖지는 않습니다. 필드가 TaskNotes 속성에 어떻게 대응하는지 정리했습니다.
각 필드가 가는 곳
| 작업 줄에서 | 작업 파일에서 | 비고 |
|---|---|---|
📅 2026-11-03 | | 이름이 같습니다. |
⏳ 2026-11-01 | | 이름이 같습니다. |
🛫 2026-11-10 | | TaskNotes에는 시작일이 없습니다. 필요하면 사용자 지정 속성으로 유지하세요. |
➕ 2026-10-01 | | ISO 타임스탬프로 기록됩니다. |
✅ 2026-10-20 | | 상태가 완료 값이 되고 날짜는 completedDate에 들어갑니다. |
⏫ | | TaskNotes 우선순위 목록의 값을 씁니다. 기본 목록은 다섯 단계가 아니라 세 단계이므로 다섯 단계를 어떻게 대응시킬지 정해야 합니다. |
🔁 every month | | iCalendar 규칙이 됩니다. 마감일이 2026-11-03인 every month는 DTSTART:20261103;FREQ=MONTHLY가 됩니다. |
#finance | | 해시 기호 없는 YAML 목록이 됩니다. |
🏁 delete | | TaskNotes 속성이 없습니다. TaskNotes가 무시하는 일반 frontmatter 키로 남습니다. |
🆔 parts1 | | TaskNotes 속성이 없습니다. TaskNotes의 의존 관계는 ID가 아니라 파일 경로를 가리킵니다. |
⛔ parts1 | | 상대 작업의 파일을 지정하는 blockedBy 항목이 됩니다. |
TaskNotes로 한 줄씩
TaskNotes에는 Convert to TaskNote 명령이 있고, 기능 설정에서 체크박스 옆에 변환 버튼을 켤 수도 있습니다. 둘 다 줄로 새 작업 파일을 만들고 그 줄을 파일로 가는 링크로 바꿉니다. 몇 개라면 괜찮지만 보관함 전체에는 느립니다.
TaskForge 명령줄로 한꺼번에
TaskForge는 별도 앱이며, 그 명령줄 도구(MCP 서버의 엔진이기도 합니다)는 작업을 줄과 파일 사이에서 어느 방향으로든, 하나씩 또는 일괄로 변환합니다. 작업 파일을 알아보는 방법을 알아야 하므로 작업 파일용으로 설정된 보관함이 필요합니다. 먼저 미리 보기를 하세요. 일괄 확정에는 미리 보기에서 찾은 작업 수를 다시 입력해야 하므로 범위가 넓은 쿼리가 의도보다 많이 변환하지 않습니다.
taskforge convert --query 'tag:home' --to tasknotes --folder Tasks --dry-run
taskforge convert --query 'tag:home' --to tasknotes --folder Tasks --acknowledge-count 2 실제 실행 예
- [ ] Send invoice to Acme ⏫ 🔁 every month 📅 2026-11-03 #finance ---
title: Send invoice to Acme
status: open
priority: high
tags:
- finance
- task
recurrence: "DTSTART:20261103;FREQ=MONTHLY"
due: 2026-11-03
--- ⏫ 우선순위는 high가 되었고 every month는 마감일을 기준으로 하는 iCalendar 규칙이 되었습니다. 두 번째 실행에서는 시작일, 완료 시 동작, 작업 ID가 버려지지 않고 일반 frontmatter 키(start, onCompletion, id)로 유지되었습니다. 명령은 온전히 변환할 수 없는 작업을 거부합니다. 파일을 다시 줄로 변환하면 그 파일을 식별하는 태그 task가 줄에 추가됩니다.
반대 방향으로 가려면 대상 노트를 지정하고 먼저 미리 보기를 하세요.
taskforge convert --query 'tag:home' --to inline --folder Inbox.md --dry-run 관련 페이지
자주 묻는 질문
Obsidian Tasks 이모지를 Dataview 형식으로 변환하려면 어떻게 하나요?
Obsidian Tasks에는 변환 명령이 없습니다. 정규식 찾아 바꾸기나 이 페이지의 것 같은 스크립트로 먼저 줄을 다시 쓴 뒤에 설정에서 작업 형식을 바꾸세요. 먼저 백업하고 복사본에서 시험하세요.
Obsidian Tasks에서 작업 형식을 바꾸면 기존 작업도 변환되나요?
아니요. 그 설정은 이후 플러그인이 읽고 쓰는 방식을 바꿀 뿐입니다. 옛 형식의 줄은 다시 쓰기 전까지 필드로 읽히지 않습니다.
체크박스 작업 여러 개를 TaskNotes 파일로 바꾸려면 어떻게 하나요?
TaskNotes는 한 번에 한 줄씩 변환합니다. 여러 개는 TaskForge 명령줄이 쿼리에 맞는 모든 작업을 먼저 시험 실행한 뒤 변환합니다. 어느 쪽이든 시작일처럼 TaskNotes 속성이 없는 필드가 원하는 곳에 들어갔는지 확인하세요.
Task Genius를 쓴다면 굳이 변환해야 하나요?
대개는 필요 없습니다. Task Genius는 이모지와 대괄호 필드를 같은 줄에서 읽으므로 섞인 보관함도 그대로 동작합니다. 각각 한 스타일만 읽는 Obsidian Tasks나 Dataview를 함께 쓸 때만 변환이 도움이 됩니다.
스크립트가 노트를 망가뜨릴 수 있나요?
체크박스 줄과 인식한 필드만 바꾸지만, 파일을 제자리에서 덮어씁니다. 실제 보관함에 맡기기 전에 백업하고, 복사본에서 실행하고, 비교해 보세요.