How can I kill a process when a specific string is seen on standard error?

后端 未结 5 1691
执念已碎
执念已碎 2021-01-05 00:01

I need to start a process, lets say foo. I would like to see the stdout/stderr as normal, but grep the stderr for string bar. Once

5条回答
  •  再見小時候
    2021-01-05 00:30

    I actually managed to figure out a way to do this without PID files or co-routines and in a way that should work in all POSIX-compatible shells (I've tried bash and dash). At least on systems that support /dev/fd/, but that should be pretty much all of them.

    It is a bit convoluted, though, so I'm not sure if it is to your liking.

    (                               # A
        (                           # B
            ( /tmp/foo 2>&1 1>&3 & echo $! >&4 ) |              # C
            ( tee /dev/fd/2 | ( grep -q bar && echo fin >&4 ) ) # D and E
        ) 4>&1 | (                  # F
            read CHILD
            read STATUS
            if [ "$STATUS" = fin ]; then
                kill $CHILD
            fi
        )
    ) 3>&1
    

    To explain the numerous subshells used herein:

    The body of A runs with the normal stdout duplicated to fd 3. It runs the subshells B and F with the stdout of B piped to the stdin of F.

    The body of B runs with the pipe from A duplicated on fd 4.

    C runs your actual foo command, with its stderr connected to a pipe from C to D and its stdout duplicated from fd 3; that is, restored to the global stdout. It then writes the PID of foo to fd 4; that is, to the pipe that subshell F has on its stdin.

    D runs a tee command receiving, from the pipe, whatever foo prints on its stderr. It copies that output to both /dev/fd/2 (in order to have it displayed on the global stderr) and to a pipe connected to subshell E.

    E greps for bar and then, when found, writes fin on fd 4, that is, to the pipe that F has on its stdin. Note the &&, making sure that no fin is written if grep encounters EOF without having found bar.

    F, then, reads the PID from C and the fin terminator from E. If the fin terminator was properly output, it kills foo.

    EDIT: Fixed the missing tee to copy foo's stderr to the real stderr.

提交回复
热议问题