#!/bin/bash # # Simple alarm applicaton # Example run: xalarm 1m mymessage # See discussion at https://www.reddit.com/r/Gentoo/comments/1rryh1/kalarm_replacement/ # # Parameters FULLNAME="$0" BASENAME="`basename $0`" XALARMPID="$BASHPID" XALARMPPID="$PPID" # Set alarm function xalarm_set { # Delay DELAY="${1:-10m}" # Message shift MESSAGE="${*:-Alarm!}" # Simple argument checking if ! echo $DELAY | grep -q '^[0-9]'; then xalarm_usage fi # Suppor for HH:MM format if echo $DELAY | grep -q '[0-9]:[0-9][0-9]'; then NOW="`date +%s`" LATER="`date -d $DELAY +%s`" DELAY="$(($LATER - $NOW))" if (($LATER < $NOW)); then echo "$BASENAME: deadline must be later than now" exit 1 fi fi # AT(1) implementation # Example run: xalarm 1minute mymessage #echo "xmessage $MESSAGE" | at now +$DELAY # Sleep implementation # # We put sleep into background and tell bash to wait it # This way we can grab sleep PID and then be able to reset the timer if needed sleep $DELAY & SLEEP_PID="$!" wait if [ "$ALARM_RESET" == "1" ]; then ALARM_RESET=0 echo "Resetting alarm..." xalarm_set $DELAY $MESSAGE else if which sm &> /dev/null; then #sm -f '#ffffff' -b '#1c1c1c' $MESSAGE (timer=0; while sleep 1; do let timer++; echo $MESSAGE - $timer; echo -e '\f'; done) | sm -f '#ffffff' -b '#1c1c1c' - else xmessage $MESSAGE fi fi } # List alarms function xalarm_list { # Simpler process filtering, but might collide with alarm messages #ps -U $USER -o pid,state,lstart,command | grep xalarm | grep -v grep | grep -v list | grep -v cancel | grep -v pause | grep -v resume | grep -v reset | grep -v reset-loop | \ # sed -e "s|$FULLNAME||" -e "s|/bin/bash||" | grep -v -- "sed -e" # Better, butt more difficult way to filter processes THISPID="$BASHPID" PARENTPID="$PPID" ps -U $USER -o pid,state,lstart,command | grep xalarm | grep -v grep | \ sed -e "s|$FULLNAME||" -e "s|/bin/bash||" | grep -v -- "sed -e" | grep -v "^ *$THISPID" | grep -v "^ *$PARENTPID" | grep -v "^ *$XALARMPID" | grep -v "^ *$XALARMPPID" } # Return xalarm PIDs function xalarm_pids { if [ ! -z "$1" ]; then if xalarm_list | awk '{ print $1 }' | grep -q "^$1"; then echo $1 fi else xalarm_list | awk '{ print $1 }' fi } # Send a signal to a process function xalarm_signal { local pid="$1" local signal="$2" if [ -z "$signal" ]; then signal="-TERM" fi if ps $1 &> /dev/null; then kill $signal $pid fi } # Cancel alarms function xalarm_cancel { for pid in `xalarm_pids $1`; do xalarm_signal $pid done } # Pause alarms function xalarm_pause { for pid in `xalarm_pids $1`; do xalarm_signal $pid -STOP done } # Resume alarms function xalarm_resume { for pid in `xalarm_pids $1`; do xalarm_signal $pid -CONT done } # Reset alarms function xalarm_reset { for pid in `xalarm_pids $1`; do xalarm_signal $pid -USR1 done } # Reset alarm loop counter function xalarm_reset_loop { for pid in `xalarm_pids $1`; do xalarm_signal $pid -USR2 done } # Usage function xalarm_usage { echo "usage: $BASENAME [list|cancel|kill|resume|continue|help|usage|loop|reset|reset-loop] [timedef] [message]" echo "" echo "timedef: accepts both sleep(1) and date(1) formats" exit 1 } # Respond to SIGUSR1 function xalarm_sigusr1 { if [ ! -z "$SLEEP_PID" ]; then ALARM_RESET="1" kill $SLEEP_PID 2> /dev/null fi } # Respond to SIGUSR2 function xalarm_sigusr2 { if [ ! -z "$COUNT" ]; then COUNT=0 fi } # Register traps trap xalarm_sigusr1 SIGUSR1 trap xalarm_sigusr2 SIGUSR2 # Dispatch if [ -z "$1" ] || [ "$1" == "list" ]; then xalarm_list elif [ "$1" == "cancel" ] || [ "$1" == "kill" ]; then xalarm_cancel $2 elif [ "$1" == "pause" ]; then xalarm_pause $2 elif [ "$1" == "resume" ] || [ "$1" == "continue" ]; then xalarm_resume $2 elif [ "$1" == "reset" ]; then xalarm_reset $2 elif [ "$1" == "reset-loop" ]; then xalarm_reset_loop $2 elif [ "$1" == "help" ] || [ "$1" == "usage" ]; then xalarm_usage elif [ "$1" == "loop" ]; then COUNT="0" shift while true; do let COUNT++ xalarm_set $* $COUNT done else xalarm_set $* fi