#!/usr/bin/env sh # shows due entries of bibtex file passed in # HACK: brittle! will break on various bibfile abnormities (even just on due date w/o priority) # FIXME: reimplementation with real library needed # OPTIND=1 # Reset in case getopts has been used previously in the shell. fields="due|priority|\bauthor\b|\btitle\b" filterby="due" file="${BIBFILE}" until="" show_help() { printf "%s\n" \ "" \ " bib-due Show due readings from bibtex file." \ "" \ " Usage: bib-due [-hv] -i input.bib -r 'due|priority|\bauthor|\btitle' -l 'due' -u '2020-05-12'" \ "" \ " Options:" \ "" \ " -i [bibtex-file] Input bibtex file to scrape and get items from." \ "" \ " -r [fields] Field values to read in file." \ "" \ " -l [filter] Field to use as filter entity." \ " This field is required for the scraper to pick entries up." \ "" \ " help | -h | --help Print out this help." \ "" \ " Invoked without arguments, bib-due will scrape the file defined in BIBFILE environment variable, " \ " filtering entries with the 'due' field, and getting the values for 'due', 'priority', 'author', " \ " and 'title' fields. It will then print the entries to stdout." \ "" \ " Example output line:" \ "" \ ' 2020-06-25 (1): Sergei Gerasymchuk -- “Ze” time in Ukraine (Gerasymchuk2019) ' \ "" } filter_until() { # filter for dates, with line numbers filtered=$(echo "$entries" | grep -noE '[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}') # redirect entries to fifo pipe mkfifo filteredentries finish() { rm filteredentries } trap finish EXIT echo "$filtered" >filteredentries & # find first date past until filter lastline="" while IFS= read -r line; do cond=$(printf '%s' "$line" | cut -d: -f2) cond=$(date -d "$cond" +%s) if [ "$cond" -gt "$until" ]; then lastline=$(printf '%s' "$line" | cut -d: -f1) break fi done <filteredentries # special cases all in filter, or none in filter if [ -z "$lastline" ]; then return elif [ "$lastline" -eq 1 ]; then entries="" # filter else # remove lines below found lastprinted="$((lastline - 1))" entries=$(echo "$entries" | sed -n "1,${lastprinted}p;${lastline}q") fi } filter_priority() { priority="$1" # filter for dates, with line numbers # filtered=$(echo "$entries" | grep -noE '[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}') filtered="" while [ "$priority" -gt 0 ]; do current=$(echo "$entries" | grep -E "\($priority\)") # append found to filtered entries filtered=$(printf "%s\n%s" "$filtered" "$current") # go to next 'higher' priority priority="$((priority - 1))" done # sort them chronologically again, remove empty lines entries="$(echo "$filtered" | sed -e '/^$/d' | sort)" } main() { if [ -z "$file" ]; then echo "Requires a bibtex file as argument." exit 1 fi # filter all entries for those containing filterby field (default: due) # retain values of all fields mentioned in fields variable entries=$(grep -E "^@|$fields" "$file" | awk 1 ORS=' ' | sed -E 's/@\w+\{/\n/g' | grep "$filterby" | tail -n +2 | sed -E 's/(,\s+(\w+)\s+=\s+|,\s*$)/\t/g' | awk -F'\t' '{ print $4 "\t" $5 "\t" $2 "\t" $3 "\t" $1 }') # prettify and sort the entries for display (remove {}, order by date,prio,author,title) entries=$(echo "$entries" | awk -F'\t' '{ gsub(/{/,""); gsub(/}/,""); gsub(/prio/,"",$2) } { print $1 " (" $2 "): " $3 " -- " $4 " (" $5 ")"}' | sort) if [ -n "$until" ]; then filter_until fi if [ -n "$priority" ]; then filter_priority "$priority" fi echo "$entries" } while getopts "h?i:u:r:l:p:" opt; do case "$opt" in h | \?) show_help exit 0 ;; # v) verbose=1 # ;; r) fields="$OPTARG" ;; l) filterby="$OPTARG" ;; i) file="$OPTARG" ;; u) until="$(date -d "$OPTARG" +%s)" ;; p) priority="$OPTARG" ;; esac done shift $((OPTIND - 1)) [ "${1:-}" = "--" ] && shift main "$@"