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.
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
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.
I just wanted to add this version as it can be useful for someone who also want to process the shell output in a streaming fashion. I wanted to had a version that doesnāt just do: String(take!(out)) and return everything at once.
In the example, it is just println for processing it.
using Base.Threads
function run_command_async(cmd_str)
cmd = `bash -c $cmd_str`
# Create a pipe to capture the output
out_pipe = Pipe()
err_pipe = Pipe()
# Run the command asynchronously
process = run(pipeline(cmd, stdout=out_pipe, stderr=err_pipe), wait=false)
close(out_pipe.in)
close(err_pipe.in)
# Stream output in real-time
@async while !eof(out_pipe)
line = readline(out_pipe)
println(line)
end
@async while !eof(err_pipe)
line = readline(err_pipe)
println(line)
end
# Wait for the command to finish
wait(process)
# Print any remaining output
for line in eachline(out_pipe)
println(line)
end
end
cmd_str = "for i in {1..3}; do echo \$i; sleep 0.5; done"
run_command_async(cmd_str)
println("\nCommand execution completed.")
That is useful, but note that you used out_pipe in two places which causes a data race there. You can give the async blocks a name and wait on those, instead of copying the code, to fix that race.