我使用 Ubuntu 服务器 16.04,我希望at
在当前会话中使用该实用程序从现在起 1 分钟(例如,echo
)执行某些操作,而不给出特定的日期和时间 - 仅比当前时间提前 1 分钟。
这失败了:
echo 'hi' | at 1m
at
我选择的原因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。
答案1
使用时正确的是at <timespec>
,其中<timespec>
是时间规范。您还可以使用该-f
选项来指定包含要执行的命令的文件。如果-f
并且没有使用重定向,at 将从 stdin(标准输入)读取要执行的命令。
在您的示例中,要在您按回车键(现在)后一分钟执行“某些命令”(我在下面的示例中选择“某些命令”为“echo hi”),要<timespec>
使用的目标是now + 1 minute
.因此,为了通过单行解决方案获得您想要的结果,请使用以下命令:
echo 'echo hi' | at now + 1 minute
这应该(并且将会)echo hi
在一分钟后运行该命令。这里的问题是该echo hi
命令将由虚拟 tty 中的 at 命令执行,并且输出将发送到用户的邮箱(如果配置正确 - 这需要更广泛的解释如何在UNIX 机器,不属于这个问题的范围)。最重要的是,您将无法echo hi
在发出命令的同一终端中直接看到结果。最简单的替代方法是将其重定向到“某个文件”,例如:
echo 'echo hi > /tmp/at.out' | at now + 1 minute
在上面的示例中,“some file”是/tmp/at.out
,预期结果是一分钟后创建 /tmp 下的文件at.out
并包含文本“hi”。
除了now + 1 minute
上面的示例之外,还可以使用许多其他时间规范,甚至是一些复杂的时间规范。 at 命令足够智能,可以解释人类可读的命令,如下例所示:
now + 1 day
, 13:25
, mid‐night
, noon
, ...
请参阅 at 的手册页,了解有关可能的时间规范的更多信息,因为可能的变化非常广泛,可能包括日期、相对或绝对时间等。
答案2
sleep
在子 shell 中运行:
(sleep 60; echo -e '\nhi') &
注意:在 Linux 上,您可以以秒为单位给出睡眠参数,也可以使用后缀 s/m/h/d(表示秒、分钟、小时、天)。在 BSD 上,参数必须以秒为单位
答案3
“hi”流打印在我的提示符中(在
stdin
)中,而不是在我的提示符中stdout
不,它是不是“印在你的stdin
”。
如果您按回车键,它不会尝试hi
作为命令运行。只是当光标位于提示之后时echo
打印了背景。hi
也许你想打印前导换行符, 喜欢(sleep 1m && echo -e '\nhi' &)
。 (根据echo
您的 shell 需要进行调整。或用于printf
便携性。)
我将其放在&
子 shell 内部以“否认”后台作业,因此您也可以避免[1]+ Done
.在&&
命令之间,&
适用于整个复合命令链,因此它会立即返回到 shell 提示符,而不是sleep
像您那样等待退出(sleep 1; echo ... &)
发生的情况如下(延迟 1 秒):
peter@volta:~$ (sleep 1 && echo -e '\nhi' &)
peter@volta:~$
hi
# cursor is at the start of this empty line.
Bash 不知道echo
打印了什么,所以它不知道需要重新打印提示符或清理屏幕。您可以使用 手动执行此操作control-L
。
您可以编写一个 shell 函数echo
让 bash 在完成后重新打印其提示符。只是这样做echo "$PS1"
不会重现任何已经输入的字符。 kill -WINCH $$
在我的系统上,bash 会在不清除屏幕的情况下重新打印其提示行,hi
在提示符之前单独留下一行。当 WINdow 大小改变时,SIGWINCH 会自动发送,而 bash 对它的响应恰好做了我们想要的。
它可能适用于其他 shell,但我并没有尝试使其 100% 可移植/POSIX。 (不幸的是,这仅适用于 bash4.4,不适用于 bash4.3,或者取决于我不知道的某些设置)
# bash4.4
peter@volta:~$ (sleep 2 && echo -e '\nhi' && kill -WINCH $$ &)
peter@volta:~$ ljlksjksajflasdf dfas # typed in 2 seconds
hi
peter@volta:~$ ljlksjksajflasdf dfas # reprinted by Bash because of `kill -WINCH`
您可以轻松地将其包装在一个带有 sleep 参数和消息的 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 的好分支)。或者选择一个视频文件,以便打开一个新窗口。
(sleep 1 && mpv /f/share/music/.../foo.ogg </dev/null &>/dev/null &)
您可能想要打开echo
一个新的 xterm / konsole / gnome-terminal。使用命令退出后保持终端打开的选项。
答案4
结合@Peter Cordes 的答案和这个答案 https://stackoverflow.com/questions/23125527/how-to-return-to-bash-prompt-after-printing-output-from-backgrounded-function/23125687#23125687
下面的代码来自后一个答案,我做了一些改动。编译成文件a.out(无论你喜欢什么名字)
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
char *tty = "/dev/tty";
if (argc > 1)
tty = argv[1];
int fd = open(tty, O_WRONLY);
int i;
char buf[] = "\n";
for (i = 0; i < sizeof buf - 1; i++)
if (ioctl(fd, TIOCSTI, &buf[i]))
perror("ioctl");
close(fd);
return 0;
}
然后运行下面的命令。 (我把a.out放在dir /tmp/中,你可能需要更改为你的)
(sleep 2 && echo -e '\nhi' && /tmp/a.out &)
或者
(sleep 2 && echo -e '\nhi' && /tmp/a.out /proc/$$/fd/0 &)
顺便说一句,kill -WINCH $$
我在 Gentoo 上使用 Bash 4.3 效果很好。