Climax
Climax

Reputation: 673

Bash: close if pipe IO is idle

How can I close a program if a pipe stream is idle for a period of time?

Say for instance:

someprogram | closeidlepipe -t 500 | otherprogram

Is there some program closeidlepipe that can close if idle for a period (-t 500)?

timeout can close after a period, but not with the "idle" distinction.

UPDATE

It is important to note that someprogram outputs an endless stream of binary data. The data may contain the null character \0 and should be piped verbatim.

Upvotes: 4

Views: 184

Answers (2)

Joshua
Joshua

Reputation: 43317

Here's the general form of the heart of a program that does this.

while(1) {
    struct timeval tv;
    tv.m_sec = 0;
    tv.m_usec = 500000;
    int marker = 1;
    select(1, &marker, NULL, NULL, &tv);
    if (marker == 0) exit(1);
    char buf[8192];
    int n = read(0, buf, 8192);
    if (n < 0) exit(2);
    char *b = buf;
    while (n)
    {
        int l = write(1, b, n);
        if (l <= 0) exit(3);
        b += l;
        n -= l;
     }
}

Upvotes: 1

chepner
chepner

Reputation: 531808

The builtin read has a timeout option -t.

someprogram |
  while :; do
    IFS= read -d'' -r -t 500 line
    res=$?
    if [[ $res -eq 0 || )); then
      # Normal read up to delimiter
      printf '%s\0' "$line"
    else
      # Either read timed out without reading another null
      # byte, or there was some other failure meaning we
      # should break. In neither case did we read a trailing null byte
      # that read discarded.
      [[ -n $line ]] && printf '%s' "$line"
      break
    fi
  done | 
  otherprogram

If read times out after 500 seconds, the while loop will exit and the middle part of the pipeline closes. someprogram will receive a SIGCHLD signal the next time it tries to write to its end of that pipe, allowing it to exit.

Upvotes: 1

Related Questions