问题
Crontab 确实可以工作——但只是放在一边,而不是与用户交互。如何让 crontab 通过自动感知的提示输出与当前登录的用户对话?例如,叫醒电话、闹钟,每分钟为用户 1 响一次,用户 1 不需要做任何事情来接收消息,除了在计算机前睁开眼睛和耳朵?
边注 计时,每分钟……——当然,这只是一个技术示例,实际上会选择更有意义和有用的计时。
想象一下这个
电脑 = 关闭
用户1 = 戴夫
戴夫:
*switching on computer*
*logs into his user account "dave"*
*lands in GUI desktop*
*starts mate-terminal*
检查谁已登录以及他们正在做什么:
dave@LocalMachine:~$ w
12:46:42 up 4:22, 2 users, load average: 0.18, 0.44, 0.43
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
dave tty7 :0 08:24 4:22m 6:57 0.31s mate-session
在 /tmp/ 中创建可执行 bash 脚本“alarm_clock”
dave@LocalMachine:~$ emacs -nw /tmp/alarm_clock && chmod +x /tmp/alarm_clock
# Alarm clock displaying current time and ringing.
#
# Copyleft
答案1
^G
特点
首先,当您这样做时echo '\a'
,收到铃声的终端会发出铃声。它只是一个八进制值为 007 的 ASCII 代码。它也相当于按 CTRL+G (`^G)。
来自 man 7 ascii:
Oct Dec Hex Char Oct Dec Hex Char
────────────────────────────────────────────────────────────────────────
000 0 00 NUL '\0' (null character) 100 64 40 @
001 1 01 SOH (start of heading) 101 65 41 A
002 2 02 STX (start of text) 102 66 42 B
003 3 03 ETX (end of text) 103 67 43 C
004 4 04 EOT (end of transmission) 104 68 44 D
005 5 05 ENQ (enquiry) 105 69 45 E
006 6 06 ACK (acknowledge) 106 70 46 F
007 7 07 BEL '\a' (bell) 107 71 47 G
通常这个字符是不可见的:
$ echo -e "$(date) \a"
Tue Jan 2 18:31:38 IST 2024
但是你可以通过在命令中添加-v
/标志来看到它(--show-nonprinting
cat
使用 ^ 和 M- 表示法,LFD 和 TAB 除外):
$ echo -e "$(date) \a" |cat -v
Tue Jan 2 18:31:40 IST 2024 ^G
因此,当您将此 ascii 代码写入文件(而不是终端)时,您只需将八进制 007 字符的值写入该文件。只有当您将其写入终端时,您才会听到“嘟嘟”声。
-e
不被使用echo
脚本的另一个问题是它不是以 Shebang ( #!
) 开头,而是以注释开头。在这种情况下,您#!/bin/bash
将被忽略,并且脚本可能会由 执行/bin/sh
。看man 5 crontab
:
几个环境变量由 cron(8) 守护进程自动设置。 SHELL 设置为 /bin/sh [...]
/bin/sh
您的计算机上可能有一些符合 POSIX 的 shell,其中的echo
内置函数不支持该-e
标志(POSIX 未定义该标志,通常只是一个扩展)。在这种情况下,它将使用-e
作为您想要回显的字符串的一部分。如果您想确保使用bash
,请将评论移至后舍邦。
另外,对于这种情况,最好使用printf
,例如:printf "$(date) \a\n"
将消息发送到实际终端
正如我们所说,当您将其写入文件时,您不会与任何终端交互,而只是将一些字符写入文件。如果你想将消息发送到终端,最好使用write(1)
,这会将消息发送到用户的最后一个活动 tty。例如:
printf "$(date)\a\n" | write <USER>
在这种情况下,用户将在其活动 shell 上收到一条消息,例如:
Message from root@locahost on pts/0 at 19:00 ...
Tue Jan 2 19:00:49 IST 2024
EOF
或者,如果您想将消息发送给所有用户和终端,请使用wall(1)
。
printf "$(date)\a\n" | wall