Skip to content

Instantly share code, notes, and snippets.

@top
Created May 25, 2025 01:56
Show Gist options
  • Save top/f9ace35d2026eafea7ba980466242edf to your computer and use it in GitHub Desktop.
Save top/f9ace35d2026eafea7ba980466242edf to your computer and use it in GitHub Desktop.
This script automatically converts transaction logs from Logseq into a standard CSV format for easy import into other accounting software.
#!/usr/bin/env bash
# Usage:
# add and use the template in your Logseq for all your transactions
# - transaction #financial
# template:: transaction
# Account:
# Transfer:
# Deposit/Payment:
# Withdraw/Charge:
# Note:
set -euo pipefail
IFS=$'\n\t'
# === Configuration ===
MD_DIR="$HOME/Documents/Logseq/journals" # Directory containing .md files
ENTRY_START="- transaction #financial" # Record start string
# === Output CSV Header ===
echo "Account,Transfer,Deposit/Payment,Withdraw/Charge,Note"
# === Main Logic ===
find "$MD_DIR" -maxdepth 1 -type f -name "*.md" | while read -r file; do
awk -v start="$ENTRY_START" '
BEGIN { record = ""; in_record = 0 }
# Detect the start of a transaction record
$0 ~ "^" start {
if (in_record && record != "") {
print record
}
record = $0 "\n"
in_record = 1
next
}
# Continue appending lines to current record
in_record {
if ($0 ~ /^-/) {
# New record begins
print record
record = ""
in_record = 0
next
}
record = record $0 "\n"
}
END {
if (in_record && record != "") {
print record
}
}
' "$file" | awk '
BEGIN { FS = "\n"; RS = ""; OFS = "," }
{
# Skip if contains template::
if ($0 ~ /template::/) next
# Extract fields
acc = trans = dep = with = note = ""
for (i = 1; i <= NF; i++) {
line = $i
if (line ~ /Account:/) acc = line
if (line ~ /Transfer:/) trans = line
if (line ~ /Deposit\/Payment:/) dep = line
if (line ~ /Withdraw\/Charge:/) with = line
if (line ~ /Note:/) note = line
}
# Clean field values
sub(/^.*Account:[[:space:]]*/, "", acc)
sub(/^.*Transfer:[[:space:]]*/, "", trans)
sub(/^.*Deposit\/Payment:[[:space:]]*/, "", dep)
sub(/^.*Withdraw\/Charge:[[:space:]]*/, "", with)
sub(/^.*Note:[[:space:]]*/, "", note)
# Skip if Account is empty
if (acc == "") next
# Print CSV row
printf "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n", acc, trans, dep, with, note
}
'
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment