Вы можете сделать это с помощью небольшой магии Си (подойдет и любой другой язык программирования, поддерживающий необходимые функции). Что вам нужно сделать, это:
input
устройства событий (все, что соответствует / dev / input / event [0-9] *
) select (2)
вызывается на этих устройствах в ожидании ввода с соответствующим таймаутом (период простоя)
read (2)
ввод со всех устройств, поэтому следующий вызов select (2)
не вернется немедленно Быстрый пример на C будет выглядеть так:
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <glob.h>
#include <stdlib.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
int *fds, ret, i;
glob_t glob_result;
/* find all devices matching /dev/input/event[0-9]* */
ret = glob("/dev/input/event[0-9]*", GLOB_ERR|GLOB_NOSORT|GLOB_NOESCAPE, NULL, &glob_result);
if (ret)
err(EXIT_FAILURE, "glob");
/* allocate array for opened file descriptors */
fds = malloc(sizeof(*fds) * (glob_result.gl_pathc+1));
if (fds == NULL)
err(EXIT_FAILURE, "malloc");
/* open devices */
for (i = 0; i < glob_result.gl_pathc; i++) {
fds[i] = open(glob_result.gl_pathv[i], O_RDONLY|O_NONBLOCK);
if (fds[i] == -1)
err(EXIT_FAILURE, "open `%s'", glob_result.gl_pathv[i]);
}
fds[i] = -1; /* end of array */
for (;;) {
char buf[512];
struct timeval timeout;
fd_set readfds;
int nfds = -1;
FD_ZERO(&readfds);
/* select(2) might alter the fdset, thus freshly set it
on every iteration */
for (i = 0; fds[i] != -1; i++) {
FD_SET(fds[i], &readfds);
nfds = fds[i] >= nfds ? fds[i] + 1 : nfds;
/* read everything what's available on this fd */
while ((ret = read(fds[i], buf, sizeof(buf))) > 0)
continue; /* read away input */
if (ret == -1 && errno != EAGAIN)
err(EXIT_FAILURE, "read");
}
/* same for timeout, 5 seconds here */
timeout.tv_sec = 5; /* FIXME */
timeout.tv_usec = 0;
ret = select(nfds, &readfds, NULL, NULL, &timeout);
if (ret == -1)
err(EXIT_FAILURE, "select");
if (ret == 0)
printf("Timeout: start first script\n");
} else {
printf("No timeout: start second script\n");
}
}
return 0;
}
Этот пример будет ждать ввода бесконечно. Если по прошествии 5 секунд ввод не будет получен, будет напечатано «Тайм-аут:…», если ввод будет получен «Нет тайм-аута:…»
Для дальнейшего чтения (однако вы хотите выполнить и завершить процессы) см. fork (2)
, exec (2)
и kill (2)
соответственно.Как упоминалось ранее, каждого языка, позволяющего запускать select (2)
для файлов, будет достаточно, так что вы также можете использовать Python, Ruby или что-то подобное.
Примечание: Это всего лишь пример, нужно позаботиться о дополнительных вещах. Например, это печатает «Тайм-аут» каждые 5 секунд, а не только один раз, пока не будет получен ввод, аналогично «Нет тайм-аута» появляется каждый нажатие клавиши / движение мыши.
Кроме того, это нужно будет запускать от имени root
, поскольку устройства событий ввода
никому не доступны для чтения по очевидным причинам.
Вы успешно отправили задание at
, и оно успешно распечатало дату на (ваш )терминал в /dev/pts/9
. У вас также есть оболочка, которая напечатала приглашение и должным образом ожидает вашего ввода.
Это симуляция того, что произошло:
your-prompt-here$ at -f './at-test.sh' now + 1 minutes
job 1 at Fri Mar 8 20:13:00 2019
your-prompt-here$
your-prompt-here$ 20:14:1552093897
echo I am still here
I am still here
your-prompt-here$
Как видите, моя оболочка приняла команду echo
; мой курсор просто не был там, где я «ожидал», потому что задание at
нацарапало мой терминал.