duct.py icon indicating copy to clipboard operation
duct.py copied to clipboard

Support for continuous stdin for a long-running process.

Open SpruceCloud opened this issue 2 years ago • 2 comments

For a long-running process (a shell), I would like to provide multiple commands over time and read their output, respectively.

Would it be it somehow possible to provide input, that is not one-time like stdin_bytes()? (Maybe by creating a pipe and passing it as stdin_file?)

SpruceCloud avatar Jun 08 '23 14:06 SpruceCloud

Maybe by creating a pipe and passing it as stdin_file

Yep, that's exactly what you'd want to do in this case. Here's an example of doing this with Duct:

use duct::cmd;
use std::error::Error;
use std::io::prelude::*;

fn main() -> Result<(), Box<dyn Error>> {
    let (read_pipe, mut write_pipe) = os_pipe::pipe()?;
    let handle = cmd!("wc").stdin_file(read_pipe).start()?;
    for _ in 0..10 {
        write_pipe.write_all(b"foobarbaz")?;
    }
    // Important: If we don't close our write end first, wc will wait for more input forever, and
    // handle.wait() will never return.
    drop(write_pipe);
    handle.wait()?;
    Ok(())
}

And for comparison here's an example of the same thing with std::process::Command:

use std::error::Error;
use std::io::prelude::*;
use std::process::{Command, Stdio};

fn main() -> Result<(), Box<dyn Error>> {
    let mut handle = Command::new("wc").stdin(Stdio::piped()).spawn()?;
    let mut write_pipe = handle.stdin.take().unwrap();
    for _ in 0..10 {
        write_pipe.write_all(b"foobarbaz")?;
    }
    // Important: If we don't close our write end first, wc will wait for more input forever, and
    // handle.wait() will never return.
    drop(write_pipe);
    handle.wait()?;
    Ok(())
}

oconnor663 avatar Jun 08 '23 17:06 oconnor663

One difference to be aware of between stdin_bytes and stdin_file is that the former spawns a thread for you to do the writing in the background. That's a bit expensive, but it avoids some potentially confusing deadlocks in more complex use cases. See https://github.com/oconnor663/duct.py/blob/master/gotchas.md#using-io-threads-to-avoid-blocking-children

oconnor663 avatar Jun 08 '23 17:06 oconnor663