Chris Angelico wrote:
There's a strong convention that zero == success, nonzero == failure, so this would apply as-is to a lot of programs. Obviously this shouldn't be the one and only way to run a subprocess (this is NOT a proposed change to Process.run, it's a separate function), so if you want to invoke grep(1) and accept 0 (lines found) and 1 (no lines found) but not 2 (error), then you'd make an app-specific function; but 0 vs other is common enough that I think this fits the standard library.
Example of prior art: Python's subprocess.check_call and check_output functions raise an exception on non-zero return value:
Well, ok, fair enough. But then, try to improve on the interface and preferably make it work like this: (unless there already is an easy Pike-API for this, I'm not intimately familiar with the Process-group)
// This leaves stdin and stdout and stderr unaltered Process.pipe.run("fgrep -e test").run("sort").run("wc");
string s = "Your.input.text";
// This leaves stdout and stderr unaltered Process.pipe.stdin(s).run("fgrep -e test").run("sort").run("wc");
Stdio.File in = Stdio.File("foo.bar.file"); Stdio.File out = Stdio.FakeFile();
// This leaves stderr unaltered Process.pipe.stdin(in).run("fgrep -e test").run("sort") .run("wc").stdout(out); string output = out->read();
Stdio.File in = Stdio.File("foo.bar.file"); Stdio.File out = Stdio.FakeFile(); Stdio.File devnull = Stdio.File("/dev/null","w");
// This leaves stderr unaltered, except for the "sort" run, we silence it there Process.pipe.stdin(in).run("fgrep -e test").stderr(devnull).run("sort") .run("wc").stdout(out); string output = out->read();
Stdio.File in = Stdio.File("foo.bar.file"); Stdio.File out = Stdio.FakeFile(); Stdio.File devnull = Stdio.File("/dev/null","w"); Stdio.File sortout = Stdio.FakeFile();
// This leaves stderr unaltered, except for the "sort" run, we silence it there // The stdout of sort is copied to both the sortout file, and to the wc // process (compare "man 1 tee") Process.pipe.stdin(in).run("fgrep -e test").stderr(devnull).run("sort") .tee(sortout).run("wc").stdout(out); string sortoutput = sortout->read(); string output = out->read();
In all this, yes, throw exceptions if any of the processes returns non-zero exitcodes. In essence the above interface would allow you to run arbitrarily complex (shell-like) pipes, basically supporting everything bash does too. Maybe the only thing missing here would be the ability to ignore certain signals per remainder of the process train, e.g.:
Process.pipe.stdin(in).blocksignal(SIGHUP).run("fgrep -e test") .stderr(devnull).run("sort").tee(sortout) .unblocksignal(SIGHUP).run("wc").stdout(out);
Which would tie SIGHUP to SIG_IGN for fgrep and sort, and allow it through again for wc.
As an extra convenience function, I could imagine this:
string output = Process.pipe.stdin(in).run("fgrep -e test").run("sort") .run("wc").stdoutstring;
Which would generate that output string you are after in one-go.