Collecting all output from shell commands

I added support for pipelines going into communicate and collecting the max of the error codes. Thanks for posting the original function.

Also I referenced it over here: powershell - How do I prevent an error message when using get-process for an process that does not run? - Stack Overflow

function communicate(cmd::Base.AbstractCmd, input="")
    inp = Pipe()
    out = Pipe()
    err = Pipe()

    process = run(pipeline(cmd, stdin=inp, stdout=out, stderr=err), wait=false)
    close(out.in)
    close(err.in)

    stdout = @async String(read(out))
    stderr = @async String(read(err))
    write(process, input)
    close(inp)
    wait(process)
    if process isa Base.ProcessChain
        exitcode = maximum([p.exitcode for p in process.processes])
    else
        exitcode = process.exitcode
    end

    return (
        stdout = fetch(stdout),
        stderr = fetch(stderr),
        code = exitcode
    )
end
1 Like

Would @async in stdout and stderr now be replaced with Threads.@spawn given the warning in the documentation, or would that not be an issue/appropriate here? Just asking given that this function is still likely to be widely referenced.

1 Like

Yes, though now you might want to use an IOBuffer there instead of Pipe, which will handle doing that internally

1 Like

Sorry just to clarify did you mean that with IOBuffers I don’t have to worry about using either @async or @spawn? something like

function communicate(cmd::Cmd)
    out = IOBuffer()
    err = IOBuffer()

    process = run(pipeline(cmd, stdout=out, stderr=err), wait=false)
    wait(process)

    seekstart(out)
    seekstart(err)
    
    if process isa Base.ProcessChain
        exitcode = maximum([p.exitcode for p in process.processes])
    else
        exitcode = process.exitcode
    end

    return (
        stdout = String(take!(out)),
        stderr = String(take!(err)),
        code = exitcode
    )
end

Only starting on Julia v1.11 right?

That is both right. And both wait and pipeline are redundant there, since those are also options directly of run, so can be simplified further. And the seekstart has no effect either.