Goal
I’ve been using Obsidian as the primary hub for personal notes for the past year. My daily notes act as a sort of captain’s log, and have superceded my use of a dedicated journaling app. So I exported all my journal entries to markdown, and added them to my Obsidian vault as daily notes.
In the process of migrating journal entries between apps over the years1, I must have messed up some metadata at some point, because I just realized today that all my entries before a certain point in time were wrong by one day. So I wrote a small script (below) to batch correct these files.
Setup
To help write and debug the script, I put a handful of dummy files in a staging
directory, each following the YYYY-MM-DD.md
naming convention.
We’ll use pathlib.Path(…).glob('*.md')
to get a list of markdown files in this directory.
import datetime as dt
from pathlib import Path
p = Path('staging')
all_md_files = sorted(list(p.glob('*.md')))
# Print the contents of each file
for f in all_md_files:
print('\n' + '=' * len(f.name))
print(f.name)
print('=' * len(f.name) + '\n')
with open(f, 'r') as open_file:
print(open_file.read())
=============
2013-12-31.md
=============
# 2013-12-31
This file should become 2014-01-01.
=============
2014-01-01.md
=============
# 2014-01-01
This file should become 2014-01-02.
=============
2014-01-03.md
=============
# 2014-01-03
This file should remain as 2014-01-03.
Note that these files contain the date in their names, but also as an h1
heading within the file itself, so we’ll need to change both.
The script
My original issue only affected files up to a certain date, so let’s filter the list of markdown files.
Because we are incrementing the dates of files, we’ll want to work through the list in reverse order. Before making yesterday today, we must make today tomorrow—else there will be a conflict.
selected_files = sorted([f for f in all_md_files if f.stem <= '2014-01-02'], reverse=True)
for f in selected_files:
print(f.name)
2014-01-01.md
2013-12-31.md
The actual work to be done here is relatively simple:
- Convert string to datetime, increment by 1d, convert back to string.
- Replace references to the previous date string with the new one, inside file contents.
- Rename the file itself.
def replace_in_file(fp: str, old: str, new:str) -> None:
""" Replace 'old' strings with 'new' strings in a given file (fp) """
with open(fp, 'r') as open_file:
old_contents = open_file.read()
new_contents = old_contents.replace(old, new)
with open(fp, 'w') as open_file:
open_file.write(new_contents)
for f in selected_files:
old_dt = dt.datetime.strptime(f.stem, '%Y-%m-%d')
new_dt = (old_dt + dt.timedelta(days=1))
new_ds = new_dt.strftime('%Y-%m-%d')
replace_in_file(f, f.stem, new_ds)
f.rename(f.parent / (new_ds + '.md'))
Check results
Visually inspecting the files in the staging
directory, we can see the final result matches what we hoped to achieve.
for f in sorted(list(p.glob('*.md'))):
print('\n' + '=' * len(f.name))
print(f.name)
print('=' * len(f.name) + '\n')
with open(f, 'r') as open_file:
print(open_file.read())
=============
2014-01-01.md
=============
# 2014-01-01
This file should become 2014-01-01.
=============
2014-01-02.md
=============
# 2014-01-02
This file should become 2014-01-02.
=============
2014-01-03.md
=============
# 2014-01-03
This file should remain as 2014-01-03.
If you’re running a script that modifies your files in-place like this, be sure to have recent, working backups before you start, in case something goes wrong!
comments powered by Disqus