I use a script to copy citations from Zotero to Obsidian. I’ll paste the whole script below, but the thing I’d like to modify is obsidian="obsidian://open?vault=$vault&file=$citekey.md"
The script works as intended, you select a highlighted citation in Zotero, trigger the hotkey, it opens or switches to Obsidian and then changes whichever note was active last to the note corresponding to the citation. If there was no note for this yet, it creates one with a template.
I’m hoping someone has some advice on how to modify this, so it checks if $citekey.md is already open, if so it switches to that, otherwise it creates a new tab and goes there. It’s started getting annoying when I work with several notes, and then can’t find a previous note because the script has bulldozed over it, and then I have the same note open in three different tabs.
Script and explanations
In case anyone wants to use or test this script, you do have to be aware that you need Zotero and the plugin Better BibTeX installed, plus have the “Quick Copy” option set to “Better BibTeX Citation Key Quick Copy”, otherwise the script won’t work. I have the Better BibTeX “citation key formula” set to auth + ( origyear || year ) + shorttitle(1,1)
though I don’t think it matters, as long as the names in Obsidian get the same names.
#!/bin/bash
echo -n | xclip -selection clipboard
sleep 0.5
xdotool key ctrl+shift+c
sleep 0.2
# Save the citation key from the clipboard to a variable
citekey=$(xclip -o -selection clipboard)
# Check if citekey is empty
if [[ -z "$citekey" ]]; then
echo "Error: citekey is empty. Exiting script."
exit 1
fi
sleep 0.1
# Copies selected text or highlight in Zotero to clipboard
xdotool key ctrl+c
citation="$(xsel -o -b | sed 's/\\>/>/g' | sed -E '
s/\([^)]* ([0-9a-z]+)\)[[:space:]]{2,}/\1/g;
s/^> ?["“]([^"“”]+.*[^"“”]*)["”]$/\> \1/;
s/^> ?[‘\047]([^’\047]+.*[^’\047]*)[’\047]$/\> \1/;
s/[\\*#]//g')"
sleep 0.1
# Set your vault's directory
directory="/home/ReaderGuy42/Documents/Obsidian/PhD/03 Sources"
new_file="$directory/$citekey.md"
# Set location for Zotero's BetterBibTeX .bib file
bibfile="/home/ReaderGuy42/Documents/Zotero/Library.bib"
vault="PhD"
obsidian="obsidian://open?vault=$vault&file=$citekey.md"
# Check if the citekey exists in the .bib file before proceeding
if ! grep -q "@.*{$citekey," "$bibfile"; then
echo "Error: citekey not found in .bib file. Exiting script."
exit 1
fi
# Extract the author/editor information by isolating the block for this citekey
author=$(awk -v key="$citekey" '
BEGIN {found=0}
$0 ~ "@.*{.*" key "," {found=1} # When the citekey starts
found && $0 ~ /author[[:space:]]*=/ {
sub(/.*author[[:space:]]*=[[:space:]]*[{"]/, "");
sub(/[}"].*/, "");
print;
found=0;
}
found && $0 ~ /editor[[:space:]]*=/ {
sub(/.*editor[[:space:]]*=[[:space:]]*[{"]/, "");
sub(/[}"].*/, "");
print;
found=0;
}
' "$bibfile")
title=$(grep -A1 "@.*{$citekey," "$bibfile" | grep 'title =' | sed -E 's/.*title = \{(.+)\},/\1/;s/[{}]+//g' | sed 's/\\\"a/ä/g; s/\\\"o/ö/g; s/\\\"u/ü/g; s/\\\"A/Ä/g; s/\\\"O/Ö/g; s/\\\"U/Ü/g; s/\\{\\ss\\}/ß/g; s/\\ss/ß/g')
shorttitle=$(grep -A5 "@.*{$citekey," "$bibfile" | grep 'shorttitle =' | sed -E 's/.*shorttitle = \{(.+)\},/\1/;s/[{}]+//g' | sed 's/\\\"a/ä/g; s/\\\"o/ö/g; s/\\\"u/ü/g; s/\\\"A/Ä/g; s/\\\"O/Ö/g; s/\\\"U/Ü/g; s/\\{\\ss\\}/ß/g; s/\\ss/ß/g')
year=$(awk -v key="$citekey" '
$0 ~ "@" && $0 ~ key {found=1}
found && $0 ~ /year[[:space:]]*=/ {sub(/.*year[[:space:]]*=[[:space:]]*[{"]/, ""); sub(/[}"].*/, ""); print; found=0}
' "$bibfile")
item_key=$(awk -v key="$citekey" '
$0 ~ "@" && $0 ~ key {found=1}
found && $0 ~ /file[[:space:]]*=/ {
sub(/.*storage\//, "");
sub(/\/.*/, "");
print;
found=0;
}
' "$bibfile")
abstract=$(awk -v key="$citekey" '
$0 ~ "@" && $0 ~ key {found=1}
found && $0 ~ /abstract[[:space:]]*=/ {in_abstract=1}
in_abstract {
if ($0 ~ /abstract[[:space:]]*=/) {
sub(/.*abstract[[:space:]]*=[[:space:]]*[{"]/, "", $0);
}
if ($0 ~ /[}"][[:space:]]*[,]*$/) {
sub(/[}"][[:space:]]*[,]*$/, "", $0);
in_abstract=0;
}
gsub(/\\\"a/, "ä", $0);
gsub(/\\\"o/, "ö", $0);
gsub(/\\\"u/, "ü", $0);
gsub(/\\\"A/, "Ä", $0);
gsub(/\\\"O/, "Ö", $0);
gsub(/\\\"U/, "Ü", $0);
gsub(/\{\\ss\}/, "ß", $0);
gsub(/\\ss/, "ß", $0);
gsub(/\{/, "", $0);
gsub(/\}/, "", $0);
abstract = abstract $0 " ";
}
!in_abstract && abstract {print abstract; abstract=""; found=0}
' "$bibfile")
# Handle cases where the information is not found
author=${author:-"Unknown"}
title=${title:-"Untitled"}
year=${year:-"Unknown"}
# Create the note if it doesn't already exist
if [ ! -f "$new_file" ]; then
cat <<EOF > "$new_file"
---
Authors: $author
Title: "$title"
aliases: "$shorttitle"
Year: $year
Notes: unread
Category: 🖊️
DateAdded: $(date +%Y-%m-%d)
---
> [!infoblock]-
>> [!abstract]-
>> $abstract
>
>> [!kernel]-
>> \`\`\`dataviewjs
dv.executeJs(await dv.io.load("Scripts/dv/DQLkernel.md"))
>> \`\`\`
EOF
sleep 0.3
fi
# Open the note and scroll down
xdg-open "$obsidian"
sleep 0.2
xdotool key ctrl+End
xdotool key Page_Down
# Only append citation if it's not empty
if [[ -n "$citation" ]]; then
echo -e "\n\n###### $citation" >> "$new_file"
fi
# Delete duplicate newlines to maintain order
sed -i '/./,/^$/!d' "$new_file"
# Run the external script
python3 "/home/ReaderGuy42/Documents/Obsidian/PhD/Scripts/letterize-page-numbers.py"
sleep 0.2
xdotool key ctrl+End
sleep 0.2
xdotool key Page_Down
P.S.: The letterize-page-numbers.py
is a script which gives each citation a unique identifier, so if I paste a citation from a page that already had a citation, it gives it letters, (and then also modifies the initial page number). So 5 → 5a, and subsequent citations go 5b, 5c, etc.
This way I can reference a citation via [[Smith2020What#5c]]
. I can provide that script if anyone is curious.
Thanks!