我使用 Ubuntu 服务器 16.04,并且我希望at
在当前会话中使用该实用程序在 1 分钟后执行某项操作(例如 an echo
),但没有给出具体的日期和时间 - 仅比当前时间提前 1 分钟。
这失败了:
echo 'hi' | at 1m
我选择的原因at
是sleep
因为 sleep 会妨碍当前会话,因此更适合在另一个会话中延迟命令,而不是我们大部分时间使用的命令。AFAIR,at
不这样做,不会妨碍我的会话。
更新_1
通过 Pied Piper 的回答,我尝试过:
(sleep 1m; echo 'hi') &
我对这种方法有疑问:“hi”流打印在我的主提示符内,并且还在_
包含它的主提示符下方添加了一个空的辅助提示符 ( ),请参阅:
USER@:~# (sleep 1m; echo 'hi') &
[1] 22731
USER@:~# hi
^C
[1]+ Done
更新_2
根据彼得科德的回答,我试过:
(sleep 2 && echo -e '\nhi' && kill -WINCH $$ &)
这在 Bash 4.4 中可以正常工作,但在某些旧版本中似乎不行(请参阅答案中的评论)。我个人在自己的环境中使用 Bash 4.3。
正确的用法是,时间规范
at <timespec>
在哪里。<timespec>
您还可以使用该-f
选项来指定包含要执行的命令的文件。如果-f
不使用重定向,则 at 将读取从标准输入(标准输入)执行的命令。在您的示例中,在您按下回车后一分钟(现在)执行“some command”(我在下面的示例中选择“some command”为“echo hi”),预期
<timespec>
使用的是now + 1 minute
. 因此,为了通过单线解决方案获得您想要的结果,请使用以下命令:echo 'echo hi' | at now + 1 minute
这应该(并且会)
echo hi
在一分钟后运行命令。这里的问题是该echo hi
命令将由 at 命令在虚拟 tty 中执行,并且输出将被发送到用户的邮箱(如果配置正确 - 这需要更广泛地解释如何在一台unix机器,不属于这个问题的范围)。最重要的是,您将无法echo hi
在发出命令的同一终端中直接看到结果。最简单的选择是将其重定向到“某个文件”,例如:echo 'echo hi > /tmp/at.out' | at now + 1 minute
在上面的例子中,“some file”是
/tmp/at.out
,预期的结果是at.out
/tmp 下的文件在一分钟后创建并包含文本“hi”。除了上面的
now + 1 minute
示例之外,还可以使用许多其他时间规范,甚至是一些复杂的时间规范。at 命令足够聪明,可以解释非常易读的命令,如下例所示:now + 1 day
,13:25
,mid‐night
,noon
, ...有关可能的时间规范的更多信息,请参阅 at 的手册页,因为可能的变化非常广泛,可能包括日期、相对或绝对时间等。
在子shell中运行
sleep
:注意:在 Linux 上,您可以以秒或后缀 s/m/h/d(表示秒、分钟、小时、天)给出睡眠参数。在 BSD 上,参数必须以秒为单位
不,它不是“印在你的
stdin
”上的。如果您按下回车键,它不会尝试
hi
作为命令运行。只是当光标在您的提示之后echo
打印的背景。hi
也许你想打印一个领先的换行符,比如
(sleep 1m && echo -e '\nhi' &)
. (根据需要调整echo
shell 中的。或printf
用于可移植性。)我将
&
subshell 放在里面来“拒绝”后台作业,这样你也可以避免[1]+ Done
. 在&&
命令之间,适用于整个复合命令链,因此它会立即返回到 shell 提示符,而不是像您使用&
的那样等待退出sleep
(sleep 1; echo ... &)
这是发生的事情(延迟 1 秒):
Bash 不知道
echo
打印了什么,所以它不知道它需要重新打印它的提示或清理屏幕。您可以使用 手动执行此操作control-L
。您可以编写一个 shell 函数,让 bash 在完成后重新打印其提示
echo
。只是这样做echo "$PS1"
不会重现任何已经输入的字符。kill -WINCH $$
在我的系统上让 bash 在不清除屏幕的情况下重新打印其提示行,hi
在提示之前单独保留一行。当 WINdow 大小发生变化时会自动发送 SIGWINCH,而 bash 对它的响应恰好符合我们的要求。它可能适用于其他 shell,但我并没有试图让这个 100% 可移植/POSIX。(不幸的是,这只适用于 bash4.4,不适用于 bash4.3,或者取决于我不知道的某些设置)
您可以轻松地将其包装在一个带有 sleep arg 和消息的 shell 函数中。
bash 4.3 在 SIGWINCH 之后不会重新打印它的提示,所以这在那里不起作用。我
shopt -s checkwinsize
在两个系统上都启用了,但它只适用于 Bash 4.4 系统(Arch Linux)。如果它不起作用,您可以尝试
(sleep 2 && echo -e '\nhi' && echo "$PS1" &)
,如果命令行为空,它会“起作用”。(它也忽略了设置的可能性PROMPT_COMMAND
。)当计时器触发时,没有真正干净的方法可以让终端输出与您以后可能在终端上执行的任何操作混合。如果您正在滚动某些内容
less
,您很容易错过它。如果您正在寻找具有交互式结果的内容,我建议您播放音频文件。例如使用命令行播放器
mpv
(MPlayer2 的好分支)。或者选择一个视频文件,以便打开一个新窗口。您可能希望
echo
打开一个新的 xterm / konsole / gnome-terminal。使用在命令退出后保持终端打开的选项。那失败了,因为您正在管道输出
echo "hi"
,这只是hi
到at
,但at
期望它的输入可以由默认系统 shell 执行(通常是 bash,但有时会因系统而异)。这个:
将实现您似乎正在尝试做的事情。它使用称为“here document”的 shell 构造,这通常是执行此类操作的公认方式(因为它比使用
echo
命令更好地处理多行,并且不需要像您需要的那样创建新文件)cat
),并使用以下转换为更复杂的等价物echo
:可能值得注意的是,
at
它将任何命令输出邮寄给调用该at
命令的用户,而不是像在子shell 中延迟使用的命令那样将输出写入终端sleep
。特别是,这意味着除非您对系统进行了一些自定义,或者打算读取本地邮件假脱机,否则您将无法获得通过at
.结合@Peter Cordes的答案和这个答案 https://stackoverflow.com/questions/23125527/how-to-return-to-bash-prompt-after-printing-output-from-backgrounded-function/23125687#23125687
下面的代码来自后一个答案,我做了一点改动。将其编译到文件 a.out(您喜欢的任何名称)
然后运行下面的命令。(我把 a.out 放在 /tmp/ 目录下,你可能需要换成你的)
或者
顺便说一句,
kill -WINCH $$
在 Gentoo 上使用 Bash 4.3 对我来说效果很好。基于上面的答案,您可以让嵌入式命令将其输出定向到您的终端,如下所示:
echo "echo hi >$(tty); kill -WINCH $$" | at now + 1 minute
该
tty
命令返回当前终端的设备路径,将其包含在$(...)
bash 中,在子 shell 中执行它,并且 kill 命令向当前进程发送一个信号,让 bash 重新打印其 $PS1 提示符。