Is there a way to make use of the command leave
and the command say
(MacOS) to be notified by the built in voice system?
I can do echo hello | say
on the command line.
leave
outputs Time to leave!
how can this output be piped to say
once it appears?
When I issue this command it’s just hanging. (no leave process is created)
# one minute from now leave +0001 Alarm set for Fri Jun 3 15:55:05 CEST 2022. (pid 37692) pgrep leave 37692 # triggers: Time to leave! # one minute from now piped to say # this one is just hanging there.... (no leave process created) leave +0001 | say
man leave
LEAVE(1) BSD General Commands Manual LEAVE(1) NAME leave -- remind you when you have to leave SYNOPSIS leave [[+]hhmm] DESCRIPTION The leave utility waits until the specified time, then reminds you that you have to leave. You are reminded 5 minutes and 1 minute before the actual time, at the time, and every minute thereafter. When you log off, leave exits just before it would have printed the next message. The following options are available: hhmm The time of day is in the form hhmm where hh is a time in hours (on a 12 or 24 hour clock), and mm are minutes. All times are converted to a 12 hour clock, and assumed to be in the next 12 hours. + If the time is preceded by `+', the alarm will go off in hours and minutes from the current time. If no argument is given, leave prompts with "When do you have to leave?". A reply of newline causes leave to exit, otherwise the reply is assumed to be a time. This form is suitable for inclusion in a .login or .profile. To get rid of leave you should either log off or use `kill -s KILL' giving its process id. SEE ALSO calendar(1) HISTORY The leave command appeared in 3.0BSD. BSD April 28, 1995 BSD
Thank you!
Advertisement
Answer
It sounds like leave
writes one line of output per day. If say
is trying to read all of stdin at a go (or otherwise do any kind of a read that is not one-character-at-a-time stopping at the first newline), the buffer will never be full enough for its read to complete in a reasonable time period.
The bash read
builtin does these (inefficient) one-character-at-a-time reads, and so is able to get content from a pipeline more appropriately (as long as leave
is overriding libc’s default buffering behavior, which switches from line-buffered to fully-buffered when output is not direct to a TTY; but if it doesn’t do this, that’s a bug you should report to your OS vendor).
To run a new copy of say
for each line of output from leave
:
leave | while IFS= read -r line; do say <<<"$line"; done
To wait until leave
has some output, run say
exactly once, then exit:
leave | { IFS= read -r line; say <<<"$line"; }
All of this can be put in the background if you choose. For example:
{ leave | { IFS= read -r line; say <<<"$line"; } } </dev/null >leave-say.log 2>&1 & disown -h "$!"
…will do an equivalent of running the above code in the background with nohup
, writing any errors to leave-say.log
instead of nohup.out
.