bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Unexpected behaviour when using process substitution with stdout and std


From: earnestly
Subject: Unexpected behaviour when using process substitution with stdout and stderr
Date: Sun, 11 Jul 2021 11:09:10 +0100

GNU bash, version 5.1.8(1)-release (x86_64-pc-linux-gnu)

I have attempted to use process substitution in order to feed the
output of a command into two filters, one for handling stdout and the
other for stderr.

Prior to this I was using POSIX sh and named pipes to achieve this but
decided to try bash with its >() and <() notation.

Perhaps I am misunderstanding how this works because I found them to be
unusable in this context.

What appears to be happening is that the output from standard error is
being mixed into the function handling standard out, even more
surprisingly that xtrace output is also being consumed and filtered as
well.

I don't quite know how to describe what's happening so I have provided a
small demonstration/reproducer instead:

#!/bin/bash --

generate() {
    for ((i=0; i<10; ++i)); do
        if ((RANDOM % 2)); then
            printf 'generate to stdout\n'
        else
            printf 'generate to stderr\n' >&2
        fi
    done
}

stdout() {
    local line

    while read -r line; do
        printf 'from stdout: %s\n' "$line"
    done
}

stderr() {
    local line

    while read -r line; do
        printf 'from stderr: %s\n' "$line"
    done
}

# Using process substitution.
unexpected() {
    # This is particularly dangerous when the script is executed under `bash -x'
    # as the xtrace output is read as standard input to the `stdout' function.
    generate > >(stdout) 2> >(stderr)
    wait

    # Example output:
    # from stdout: generate to stdout
    # from stdout: generate to stdout
    # from stdout: from stderr: generate to stderr
    # from stdout: from stderr: generate to stderr
    # from stdout: from stderr: generate to stderr
    # from stdout: generate to stdout
    # from stdout: from stderr: generate to stderr
    # from stdout: generate to stdout
    # from stdout: from stderr: generate to stderr
    # from stdout: from stderr: generate to stderr
}

# Using named pipes.
expected() {
    mkfifo a b
    trap 'rm a b' EXIT

    generate > a 2> b &

    stdout < a &
    stderr < b &
    wait

    # Example output:
    # from stdout: generate to stdout
    # from stderr: generate to stderr
    # from stdout: generate to stdout
    # from stderr: generate to stderr
    # from stdout: generate to stdout
    # from stdout: generate to stdout
    # from stderr: generate to stderr
    # from stdout: generate to stdout
    # from stdout: generate to stdout
    # from stderr: generate to stderr
}



reply via email to

[Prev in Thread] Current Thread [Next in Thread]