我怎样才能结合离开和说的命令?

How can I combine the commands leave and say?

有没有办法利用内置语音系统通知命令leave和命令say (MacOS)?

我可以在命令行上echo hello | say

leave 输出 Time to leave! 这个输出一旦出现如何通过管道传送到 say

当我发出这个命令时,它只是挂起。 (没有创建请假流程)

# 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

男人离开

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

谢谢!

听起来像leave每天写一行输出。如果 say 试图一次读取所有标准输入(或以其他方式进行任何类型的读取 not one-character-at-a-time 在第一个换行符处停止),缓冲区永远不会满到无法在合理的时间段内完成读取。

bash read 内置函数执行这些(低效的)one-character-at-a-time 读取,因此能够更适当地从管道获取内容(只要 leave正在覆盖 libc 的默认缓冲行为,当输出不直接到 TTY 时,它从 line-buffered 切换到 fully-buffered;但如果它不这样做,这是一个错误,你应该报告给你的 OS供应商)。


运行 say 的每行输出的新副本 leave:

leave | while IFS= read -r line; do say <<<"$line"; done

等到leave有一些输出,运行 say恰好一次,然后退出:

leave | { IFS= read -r line; say <<<"$line"; }

如果您愿意,所有这些都可以放在后台。例如:

{ leave | { IFS= read -r line; say <<<"$line"; }
} </dev/null >leave-say.log 2>&1 & disown -h "$!"

...将在后台使用 nohup 执行相当于 运行 上述代码的操作,将任何错误写入 leave-say.log 而不是 nohup.out

leave 所做的是派生一个后台进程,在 STDOUT 上提供离开消息。当 fork 完成时,child 进程从其 parent 继承 STDOUT。当 parent 死亡时,child 保持管道中下一个进程的 STDIN 打开。因此,

leave +0002  | sed 's/o/OOOO/g'

似乎挂起,直到 child 进程被终止。

正确的解决方案是将管道的其余部分设置为背景:

leave  +0002  | sed 's/o/OOOO/g' &

然后产生:

Just OOOOne mOOOOre minute!
Time tOOOO leave!

或者,在您的情况下:

leave  +0002  |say &

终止 child 进程将停止 say 形式 'hanging'。 child 的 PID 在消息 Alarm set for xx.xx. (pid 3311636) 中给出。您可以通过从不同的 window.

杀死 child 来验证这一点

不是的,你不离开,child进程不会死,只是时不时的唠叨个不停。这意味着 say

  • 说“pid 的警报设置(parent 的输出)
  • 挂起等待输入
  • 说“再等一分钟!” (来自 child 的输出)
  • 再挂一分钟
  • 说“该走了”(child 的输出)
  • 再挂一分钟
  • 说“该走了”(child 的输出)

(重复最后两行直到 child 被杀死)

这也与 say 的 Macos 联机帮助页一致,其中指出:

If the input is a TTY, or if no text is specified, the typed input text will be spoken line by line