I'm working on a bash script that displays a random ANSI art banner on the top 16 lines of the screen, and then the project view of my todo.txt list in the remaining lines. This is intended to live in one pane of my tmux window, so that the right third of my screen (roughly 80x48 characters) is showing my todo list at all times.
Right now I've got the banner randomizing on load, and then the todo list updates via fswatch whenever I add or remove something. I would also like to update the banner once every 15 minutes or so, so I'd like to use something like watch to run the command to cat a random ANSI banner on a 15 minute interval, but when using watch, the banner portion of the script just blanks out the entire screen. (the code below has a 10 second interval used for testing)
Is there a better way to be doing this, or a way to get watch to start outputting the banners correctly?
Here's the script:
#!/bin/bash
clear
banner.sh
/usr/local/bin/todo.sh projectview | fold -w 80 -s
watch -t -c -n 10 banner.sh # this just gives me a blank screen and hangs
fswatch -l 1 -o --event=Updated -e "~/.todo/.*" -i "todo.txt" ~/.todo | while read;
do
tput cup 18 0 && tput ed && /usr/local/bin/todo.sh projectview | fold -w 80 -s # draw the todo list starting on the 18th line.
done
And here's banner.sh:
#!/bin/bash
filename=`ls -d ~/banners/* | shuf -n 1`
tput cup 0 0 && cat $filename && echo ""
It would appear that cat won't produce colored output in a format that watch will accept, as watching ls or some other colored output works fine, but nothing involving cat and colored output will do anything other than blank the screen.
My answer involved ditching watch and just combining the scripts, running a bash loop in the background which updates the banner every 60 seconds. Unfortunately the writes to STDOUT are not atomic for either this loop or for the todo list, so I had to simply update variables containing the banner and the list, and update the entire screen every time the list file changes or it's 60 seconds and it's time for a new banner.
This isn't ideal, because I'm redrawing a bunch of stuff that I don't have to redraw, but it's the only way to get around the fact that I can't find a way to make the writes to STDOUT atomic.
#!/bin/bash
clear
# choose a random banner and initialize variables
filename=`ls -d ~/banners/*.ans | shuf -n 1`
banner=$(head -c -1 $filename)
function todo {
# move to the top left of the screen but don't clear
tput cup 0 0
# display the banner
echo "${banner}"
# make sure we're on line 16
tput cup 16 0
# update the todo list, so that it will clear each line to the end
todolist=$(/usr/local/bin/todo.sh today | fold -w 80 -s | sed -r 's/$/\\033\[K/g')
# display the todo list
echo -e "${todolist}"
# clear the rest of the screen
tput ed
}
# CTRL-C exits cleanly, killing the banner process that was running in the background
trap 'trap - SIGTERM && tput cnorm && clear && kill 0' SIGINT SIGTERM EXIT
while true; do
# choose a new banner
filename=`ls -d ~/banners/*.ans | shuf -n 1`
banner=$(head -c -1 $filename)
# redraw the screen
todo
# do this every 60 seconds
sleep 60
done &
# make the cursor invisible for now
tput civis
fswatch -l 1 -o --event=Updated -e "~/.todo/.*" -i "todo.txt" ~/.todo | while read;
do
# redraw the screen
todo
done
# make the cursor visible again
tput cnorm
exit