【问题标题】:Reading with cat: Stop when not receiving data用 cat 读取:没有收到数据时停止
【发布时间】:2011-11-08 09:29:40
【问题描述】:

有什么方法可以告诉cat 命令在没有收到任何数据时停止读取?可能有一些“超时”来指定没有数据传入的时间。

有什么想法吗?

【问题讨论】:

  • 你不是在找read吗?
  • 猫 $fifo |而数控...

标签: linux shell unix sh cat


【解决方案1】:

有一个timeout(1) 命令。示例:

timeout 5s cat /dev/random

取决于你的情况。例如。您使用 -e 运行 bash 并正常关注退出代码。

timeout 5s cat /dev/random || true

【讨论】:

  • 如果 /dev/random 超过 5s 没有输入,这会取消 cat 吗?
  • 不,这只会阻止猫。然后,您可以分析输出以查看是否存在某些内容。
  • 但我想停止 cat 只是在 /dev/random 超过 x 秒没有更多数据时
  • 很高兴了解timeout,但请注意它是一个 GNU 实用程序(换句话说:不是 POSIX 实用程序集的一部分,因此并非在所有平台)。
  • @MichałŠrajer 好主意,不幸的是这会导致退出代码 124 超时 :)
【解决方案2】:

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 更好,如果它使故事听起来更好,我并没有超过一点小修正主义:-)

【讨论】:

  • puuuh 我想我不明白。我对 c 不太常见。
  • @Kai,检查更新,我已经编写了一个基于 snaildog 程序,它可以满足您的需求。
  • 在运行dog 时,如果我每秒输入一个字母(不返回),那么无论如何我都会超时。换句话说 - 选择查看行缓冲数据。
  • 好的,这看起来很不错。我怎样才能将它与猫之类的东西一起使用?例如我想说“dog /dev/input/event0”
  • Michał,是的,行缓冲会影响这种情况,在这种情况下,您应该使用 setvbuf 使其无缓冲。
【解决方案3】:

mbuffer 及其 -W 选项对我有用。

我需要将stdin 接收到一个文件,但是有一个空闲超时:

  • 我实际上不需要连接多个来源(但也许有一些方法可以为此使用 mbuffer。)
  • 我不需要cat 的任何可能的输出格式选项。
  • 我不介意mbuffer 带来的进度条。

根据链接手册页中的建议,我确实需要添加 -A /bin/false 来禁止警告。我将stdin 复制到具有 10 秒空闲超时的文件的调用最终看起来像

mbuffer -A /bin/false -W 10 -o ./the-output-file

【讨论】:

    【解决方案4】:

    这是 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 的狗基本相同。 它作为cat 工作,没有参数 - 捕获标准输入。作为第一个参数,提供超时秒数。

    一个限制(也适用于 dog) - 行是行缓冲的,因此您有 n 秒的时间提供一行(不是任何字符)来重置超时警报。这是因为 readline。

    用法

    而不是可能无穷无尽:

    cat < some_input > some_output
    

    您可以将上面的代码编译到 timeout_cat 并且:

    ./timeout_cat 5 < some_input > some_output
    

    【讨论】:

    • 抱歉,我无法正常工作。我试过“./timeout-cat /dev/input/event4 5”(event4是我的键盘)
    • 不,它的行为就像cat 命令,没有任何参数。唯一的参数是超时。
    • paxdiablo 的解决方案有什么不同?这只是设计问题吗?
    • 我试过 "./timeout_cat 5 /dev/input/mouse0" -> 只是在 5 秒后终止,前后没有任何输出......
    • @Kai:(有什么区别)它的作用或多或少相同,但方式不同。我们都是来学习的,对吧?
    【解决方案5】:

    尝试考虑tail -f --pid 我假设您正在阅读一些文件,并且当制作人完成时(走了?)您停止了。

    将处理 /var/log/messages 直到 watcher.sh 完成的示例。

    ./watcher.sh&
    tail -f /var/log/messages --pid $! | ... do something with the output
    

    【讨论】:

    • 不错。不幸的是,它不在我的tails 上。我希望它是 Gnu-only。
    【解决方案6】:

    我在通过 adb shell 读取 tty 端口时遇到了相同的 cat 命令阻塞问题,但没有找到任何解决方案(超时命令也不起作用)。下面是我在我的 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])
    

    【讨论】:

    • 不知道怎么检测数据缺失,但是不会用信号来控制cat
    【解决方案7】:

    简单地猫,然后在 5 秒后杀死猫。

    cat xyz & sleep 5; kill $!
    

    在 5 秒后获取 cat 输出作为回复

    reply="`cat xyz & sleep 5; kill $!`"
    echo "reply=$reply"
    

    【讨论】:

    • 如果数据生成过程在某个未指定的时间(可能是一分钟,可能是一天)输出然后停止怎么办?您只会得到前五秒 - 即使源仍在输出数据。
    • 是的,事实就是如此。因此,您必须使用此逻辑的最大可能超时。 IE。什么时候回复对你没用。
    • 重点是,最大可能的超时时间是未知的;并收到通知“该进程可能在上周的某个时间完成了数据输出(或者可能没有,也许我们只是杀死了它)”比没用更糟糕。
    • 换句话说:“我有一辆汽车,油箱里装满了油,引擎还在运转。告诉我什么时候汽油用完了。” “好吧,在固定超时后关闭引擎并假装那是正确的时刻。”看?超时很可能会太低(仍然有足够的燃料)或太高(很久以前燃料已经耗尽);您不太可能提前猜到它是正确的。
    • 您可以将输出从 cat 重定向到某个文件,并不时轮询该文件以查看结果。然后,当您对回复感到满意时,您可以不使用超时,而是杀死猫。实际上,我认为我的回答是针对 Kai 页面顶部的问题。你的情况是另一种情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-29
    • 2014-06-17
    • 2014-09-14
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    相关资源
    最近更新 更多