有没有办法告诉cat
命令在不接收数据时停止读取?也许可以使用一些“超时”来指定多久没有数据进入。
有什么想法吗?
有一个 timeout(1)
命令。例如:
timeout 5s cat /dev/random
timeout 5s cat /dev/random || true
cat
本身不会。它会读取输入流,直到被告知已到达文件的末尾,如果必要,会阻塞输入。
没有任何东西可以阻止您编写自己的cat
等效程序,该程序将使用select
在标准输入上超时,如果没有足够快的输入,则退出。
实际上,我曾经编写过一个snail
程序(因为蜗牛比猫慢),它需要一个额外的参数来指定每秒输出的字符数,从而缓慢输出文件(a)。
因此,snail 10 myprog.c
将以每秒十个字符的速度输出myprog.c
。我想不起来为什么会这样做了 - 我怀疑当时只是闲着无聊,等待一些真正的工作。
既然你遇到了麻烦,这里有一个dog.c
版本(基于我前面提到的snail
程序),可以实现你想要的功能:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/select.h>
static int dofile (FILE *fin) {
int ch = ~EOF, rc;
fd_set fds;
struct timeval tv;
while (ch != EOF) {
// Set up for fin file, 5 second timeout.
FD_ZERO (&fds); FD_SET (fileno (fin), &fds);
tv.tv_sec = 5; tv.tv_usec = 0;
rc = select (fileno(fin)+1, &fds, NULL, NULL, &tv);
if (rc < 0) {
fprintf (stderr, "*** Error on select (%d)\n", errno);
return 1;
}
if (rc == 0) {
fprintf (stderr, "*** Timeout on select\n");
break;
}
// Data available, so it will not block.
if ((ch = fgetc (fin)) != EOF) putchar (ch);
}
return 0;
}
int main (int argc, char *argv[]) {
int argp, rc;
FILE *fin;
if (argc == 1)
rc = dofile (stdin);
else {
argp = 1;
while (argp < argc) {
if ((fin = fopen (argv[argp], "rb")) == NULL) {
fprintf (stderr, "*** Cannot open input file [%s] (%d)\n",
argv[argp], errno);
return 1;
}
rc = dofile (fin);
fclose (fin);
if (rc != 0)
break;
argp++;
}
}
return rc;
}
然后,你可以简单地运行dog
而不带参数(这样它就会使用标准输入)。在五秒钟没有任何活动之后,它将输出:
*** Timeout on select
(a) 其实,它被称为slowcat
,但是snail
更加优美,如果这样能让故事听起来更好,我不介意进行一些小的修正 :-)
dog
时,如果我每秒钟输入一个字母(不换行),那么我仍然会超时。换句话说 - 选择查看行缓冲数据。 - Michał Šrajermbuffer
的 -W
选项对我很有用。
我需要将 stdin
沉淀到文件中,但带有空闲超时:
mbuffer
的方法)。cat
的可能的输出格式选项。mbuffer
提供的进度条。我需要添加 -A /bin/false
来抑制警告,基于链接页面中的建议。我的调用复制 stdin
到文件中,带有 10 秒的空闲超时,最终看起来像这样:
mbuffer -A /bin/false -W 10 -o ./the-output-file
这里是 timeout-cat 的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void timeout(int sig) {
exit(EXIT_FAILURE);
}
int main(int argc, char* argv[]) {
int sec = 0; /* seconds to timeout (0 = no timeout) */
int c;
if (argc > 1) {
sec = atoi(argv[1]);
signal(SIGALRM, timeout);
alarm(sec);
}
while((c = getchar()) != EOF) {
alarm(0);
putchar(c);
alarm(sec);
}
return EXIT_SUCCESS;
}
它基本上与paxdiablo的dog相同。
它作为一个没有参数的cat
工作 - 将stdin连接起来。第一个参数提供超时秒数。
一个限制(也适用于dog) - 行是行缓冲的,因此您有n秒钟提供一行(而不是任何字符)以重置超时警报。这是由于readline。
用法:
代替潜在的无限期:
cat < some_input > some_output
你可以将上面的编译代码命名为timeout_cat并运行:
./timeout_cat 5 < some_input > some_output
尝试考虑使用tail -f --pid命令。我假设您正在读取某个文件,当生产者完成(离开?)时,您会停止。
以下是一个示例,它将处理/var/log/messages文件,直到watcher.sh完成。
./watcher.sh&
tail -f /var/log/messages --pid $! | ... do something with the output
我遇到了通过adb shell在tty端口上读取时cat命令阻塞的问题,但是没有找到任何解决方案(timeout命令也不起作用)。以下是我在我的Python脚本中使用的最终命令(在Ubuntu上运行),使其非阻塞。希望这能帮助到某些人。
bash_command = "adb shell \"echo -en 'ATI0\\r\\n' > /dev/ttyUSB0 && cat /dev/ttyUSB0\" & sleep 1; kill $!"
response = subprocess.check_output(['bash', '-c', bash_command])
简单地将猫合并,然后在5秒钟后杀死猫。
cat xyz & sleep 5; kill $!
在5秒后作为回复获取猫的输出
reply="`cat xyz & sleep 5; kill $!`"
echo "reply=$reply"