Dual-command pipeline #br6 - cannot get partial output

I’m stuck on Stage #BR6.

Specifically this test:

remote: [tester::#BR6] [setup] echo -e “1. blueberry grape\n2. banana pear\n3. strawberry pineapple” > “/tmp/owl/file-68”
remote: [your-program] $ tail -f /tmp/owl/file-68 | head -n 5
remote: [tester::#BR6] Didn’t find expected line.
remote: [tester::#BR6] Expected: “1. blueberry grape”
remote: [tester::#BR6] Received: “” (no line received)

I implemented pipes between generic (non-embedded) commands, and it works as expected, except the case when STDOUT is not closed, like the case with tail -f.

The problem description talks about this example and explains that head -n 5 should print the partial output from tail even when less than 5 lines are available. My code only prints the output after all 5 lines are present - I assume that’s why the test fails with Received: "" (no line received).

The strange thing is I cannot make this scenario behave as explained even in my OS terminal. I’m on 25.10 Kubuntu. I tried both zsh and bash - both behaves the same way as my own code: only printing when all 5 lines are available. I tried Except’s unbuffer and stdbuf -o0 / -oL - nothing makes head print the initial 3 lines.

I also tried force flushing both stdout from head and the writer pipe from tail- no difference.

Readings suggest unbuffer and stdbuf should be able to influence the buffering from page/eof triggered to line/immediate - but I don’t see that at all.

My questions are:

  1. Am I interpreting the problem correctly? Should head -n 5 start printing before all 5 lines are there?
  2. If so - how can I make this work in a generic Linux shell?

My code is at: https://git.codecrafters.io/8e7d70115cf7a285 (main.rs : line 443)

The idea is very basic, piping child processes - showing it in a simplified way:

    let (reader, writer) = std::io::pipe().unwrap();

    let mut child1 = std::process::Command::new("tail")
        .arg("-f")
        .arg("/tmp/foo")
        .stdout(writer)
        .spawn()
        .unwrap();

    let mut child2 = std::process::Command::new("head")
        .arg("-n")
        .arg("5")
        .stdin(reader)
        .spawn()
        .unwrap();

    child1.wait().unwrap();
    child2.wait().unwrap();

I was desperately trying out different ways of handling the last process of the pipe and somehow managed to make the test pass - however the behaviour is still the same - no partial output. So at this point I feel I don’t understand what is incorrect - my system or my understanding of the problem / test.

In any ways if others fall into this - what I made:

  • I use std::io::pipe() to connect piped commands
  • the last process is also spawn()-ed instead of blocking with output() and using Stdio::inherited() for the process’ stdout override.

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.