233 lines
5.9 KiB
Bash
Executable File
233 lines
5.9 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
# This file defines track - a minimalist data tracker
|
|
|
|
# Copyright (C) 2024 James Tomasino
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#-----------------------------------------------------------------------
|
|
|
|
version="2024.04.15"
|
|
|
|
show_help () {
|
|
cat > /dev/stdout << END
|
|
track [options...] <metric> [<value>]
|
|
|
|
DIRECTORY:
|
|
If the environment variable \$TRACK_DIR is set, track will store
|
|
all data in that location. Otherwise the default is the current
|
|
working directory.
|
|
|
|
USAGE:
|
|
track weight 150 Log 150lbs for today's weight
|
|
track steps +500 Increase the numeric log of today's steps by 500
|
|
track -n 10 calories Show last 10 days calorie values
|
|
track mood Show last value logged for mood
|
|
|
|
OPTIONS:
|
|
-a Show all values of metric
|
|
-n N Show N values of metric
|
|
-x Remove metric file
|
|
-c Output CSV
|
|
-l List metrics being tracked
|
|
-h Show this help
|
|
-v Show current version info
|
|
-d Debug mode
|
|
END
|
|
}
|
|
|
|
# Determine tracking directory and ensure it is a directory
|
|
TRACK_DIR=${TRACK_DIR:-.}
|
|
if [ -f "$TRACK_DIR" ]; then
|
|
TRACK_DIR="$(dirname "${TRACK_DIR}")"
|
|
fi
|
|
|
|
arg_metric=""
|
|
arg_value=""
|
|
arg_listnum=""
|
|
arg_remove=""
|
|
flag_options="hvdan:x:lc"
|
|
flag_debug=0
|
|
flag_help=0
|
|
flag_listall=0
|
|
flag_listnum=0
|
|
flag_remove=0
|
|
flag_version=0
|
|
flag_shortlist=0
|
|
flag_csv=0
|
|
|
|
parse_input () {
|
|
if ! parsed=$(getopt ${flag_options} "$@"); then
|
|
printf "Invalid input\\n" >&2
|
|
exit 2
|
|
fi
|
|
|
|
eval set -- "${parsed}"
|
|
|
|
while true; do
|
|
case "$1" in
|
|
-h)
|
|
flag_help=1
|
|
shift
|
|
;;
|
|
-v)
|
|
flag_version=1
|
|
shift
|
|
;;
|
|
-d)
|
|
flag_debug=1
|
|
shift
|
|
;;
|
|
-a)
|
|
flag_listall=1
|
|
shift
|
|
;;
|
|
-n)
|
|
flag_listnum=1
|
|
shift
|
|
arg_listnum="$1"
|
|
shift
|
|
;;
|
|
-x)
|
|
flag_remove=1
|
|
shift
|
|
arg_remove="$1"
|
|
shift
|
|
;;
|
|
-l)
|
|
flag_shortlist=1
|
|
shift
|
|
;;
|
|
-c)
|
|
flag_csv=1
|
|
shift
|
|
;;
|
|
--)
|
|
shift
|
|
break
|
|
;;
|
|
*)
|
|
printf "Internal error: %s\\n" "$1" >&2
|
|
exit 3
|
|
;;
|
|
esac
|
|
done
|
|
|
|
while [ "$#" -gt 0 ]; do
|
|
if [ -z "${arg_metric}" ]; then
|
|
arg_metric="$(printf "%s" "${1}" | tr '[:upper:]' '[:lower:]')"
|
|
shift
|
|
else [ -z "${arg_value}" ]
|
|
arg_value="$*"
|
|
break
|
|
fi
|
|
done
|
|
}
|
|
|
|
main () {
|
|
parse_input "$@"
|
|
|
|
if [ ${flag_shortlist} -gt 0 ]; then
|
|
out=$(find "${TRACK_DIR}"/*.csv -maxdepth 1 2>/dev/null | sed -e 's/.*\///' | sed -e 's/\..*$//')
|
|
printf "%s\\n" "${out}"
|
|
exit 0
|
|
fi
|
|
|
|
if [ ${flag_version} -gt 0 ]; then
|
|
printf "%s\\n" "${version}"
|
|
exit 0
|
|
fi
|
|
|
|
if [ ${flag_help} -gt 0 ]; then
|
|
show_help
|
|
exit 0
|
|
fi
|
|
|
|
if [ ${flag_debug} -gt 0 ]; then
|
|
set -x
|
|
fi
|
|
|
|
if [ ${flag_remove} -gt 0 ]; then
|
|
rm "${TRACK_DIR}/${arg_remove}.csv"
|
|
fi
|
|
|
|
if [ "${arg_metric}" != "" ]; then
|
|
f="${TRACK_DIR}/${arg_metric}.csv"
|
|
|
|
# If new file, add header
|
|
if [ ! -f "$f" ]; then
|
|
printf "year,month,day,%s\\n" "${arg_metric}" > "$f"
|
|
fi
|
|
|
|
# Get arg parts
|
|
first_letter=$(printf %.1s "${arg_value}")
|
|
|
|
if [ "${arg_value}" != "" ]; then # add/update
|
|
d=$(date '+%Y,%0m,%0d')
|
|
l=$(sed -n "/$d/{=;}" "$f")
|
|
|
|
if [ "${first_letter}" = "+" ]; then # Add to existing value
|
|
rest="${arg_value#+}"
|
|
if [ -z "$l" ]; then
|
|
printf "%s,%s\\n" "$d" "${rest}" >> "$f"
|
|
else
|
|
val="$(sed "${l}q;d" "$f" | awk -F "," '{print $4}')" # get current value
|
|
# check if existing value is numeric before attempting to sum
|
|
if printf "%s" "$val" | grep -vEq '^[0-9]+([.][0-9]+)?$'; then
|
|
printf "Current value is not numeric. Abort.\\n"-
|
|
exit 1
|
|
fi
|
|
# check if new value is numeric before attempting to sum
|
|
if printf "%s" "$rest" | grep -vEq '^[0-9]+([.][0-9]+)?$'; then
|
|
printf "New value is not numeric. Abort.\\n"-
|
|
exit 1
|
|
fi
|
|
# sum new and previous values
|
|
newval=$((val+rest)) || exit 1
|
|
sed -i"" "$l c $d,${newval}" "$f"
|
|
fi
|
|
else # Replace existing value
|
|
if [ -z "$l" ]; then
|
|
printf "%s,%s\\n" "$d" "${arg_value}" >> "$f"
|
|
else
|
|
sed -i"" "$l c $d,${arg_value}" "$f"
|
|
fi
|
|
fi
|
|
else # display value
|
|
if [ ${flag_listall} -gt 0 ]; then
|
|
if [ ${flag_csv} -gt 0 ]; then
|
|
awk -F "," '{printf "%02d-%02d-%02d,%s\n", $1, $2, $3, $4;}' "$f"
|
|
else
|
|
awk -F "," '{printf "%02d-%02d-%02d\t%s\n", $1, $2, $3, $4;}' "$f"
|
|
fi
|
|
elif [ ${flag_listnum} -gt 0 ]; then
|
|
if [ ${flag_csv} -gt 0 ]; then
|
|
tail -n "${arg_listnum}" "$f" | awk -F "," '{printf "%02d-%02d-%02d,%s\n", $1, $2, $3, $4;}'
|
|
else
|
|
tail -n "${arg_listnum}" "$f" | awk -F "," '{printf "%02d-%02d-%02d\t%s\n", $1, $2, $3, $4;}'
|
|
fi
|
|
else
|
|
if [ ${flag_csv} -gt 0 ]; then
|
|
tail -n 1 "$f" | awk -F "," '{printf "%02d-%02d-%02d,%s\n", $1, $2, $3, $4;}'
|
|
else
|
|
tail -n 1 "$f" | awk -F "," '{printf "%02d-%02d-%02d\t%s\n", $1, $2, $3, $4;}'
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
main "$@"
|