On Thursday, 28 January 2021 at 17:18:46 UTC, Ali Çehreli wrote:
On 1/28/21 2:16 AM, Anthony wrote:

> auto p = pipeProcess("ls");
> auto q = pipeProcess("cat", stdin = p.stdout); //it would be
good to do

That would work if `cat` received the *contents* of the files (and with a "-" command line switch). Since `ls` produces file names, you would have to make the complete `cat` command line from `ls`'s output.

> Do I need to manually extract the output from
pipes.stdin.readln

Seems to be so for the `ls | cat` case. But the following `find | grep` example shows how two ends of pipes can be connected:

import std.stdio;
import std.process;
import std.range;

// BONUS: Enable one of the following lines to enjoy an issue.
// version = bonus_bug;
// version = bonus_bug_but_this_works;

void main() {
  // Writes to 'a':
  auto a = pipe();
  auto lsPid = spawnProcess([ "find", "."], stdin, a.writeEnd);
  scope (exit) wait(lsPid);

  // Reads from 'a', writes to 'b':
  auto b = pipe();
auto catPid = spawnProcess([ "grep", "-e", `\.d$` ], a.readEnd, b.writeEnd);
  scope (exit) wait(catPid);

  version (bonus_bug) {
    // Fails with the following error.
    //
    // "/usr/include/dmd/phobos/std/typecons.d(6540): Error:
    // `"Attempted to access an uninitialized payload."`"
writefln!"Some of the D source files under the current directory:\n%-( %s\n%)"(
      b.readEnd.byLine);

  } else version (bonus_bug_but_this_works) {
    // Note .take at the end:
writefln!"Some of the D source files under the current directory:\n%-( %s\n%)"(
      b.readEnd.byLine.take(1000));

  } else {
    // The results are read from 'b':
    writeln(b.readEnd.byLine);
  }
}

I've discovered a strange issue, which can be observed by uncommenting the 'version = bonus_bug;' line above. But comment that one back in and uncomment the next line, now it works. (?)

Ali


Thanks Ali.
I was messing around and below seems to work well enough for me.

```

struct AccumulatorPipe {
    Pid[] pids;

    File stdin;
    File stdout;
}

AccumulatorPipe run(string cmd) {
    AccumulatorPipe acc;

    auto p = P.pipeShell(cmd, P.Redirect.stdout);

    acc.pids ~= p.pid;
    acc.stdout = p.stdout;

    return acc;
}

AccumulatorPipe pipe(AccumulatorPipe acc0, string cmd) {
    AccumulatorPipe acc;
    Pipe p = P.pipe();

    acc.stdin = p.writeEnd;
    acc.stdout = p.readEnd;

    auto pid = P.spawnShell(cmd, acc0.stdout, acc.stdin);
    acc.pids = acc0.pids ~ pid;

    return acc;
}

void end(AccumulatorPipe acc) {
    auto pids = acc.pids ~ P.spawnShell("cat", acc.stdout);

    foreach (pid; pids) {
        P.wait(pid);
    }
}
```


So now I can do something like:
```
run("find source -name '*.d'")
        .pipe("entr ./make.d tests")
        .end(),
```


That would work if `cat` received the *contents* of the files (and with a "-" command line switch)

I was actually trying to use cat to just spit out the filenames of the directory as a test.
But I see what you mean.

Reply via email to