diff --git a/lib/internal/streams/pipeline.js b/lib/internal/streams/pipeline.js index 51bd99b654f23d..1e28a419501bce 100644 --- a/lib/internal/streams/pipeline.js +++ b/lib/internal/streams/pipeline.js @@ -265,6 +265,13 @@ function pipeline(...streams) { } else if (isStream(stream)) { if (isReadable(ret)) { ret.pipe(stream); + + // Compat. Before node v10.12.0 stdio used to throw an error so + // pipe() did/does not end() stdio destinations. + // Now they allow it but "secretly" don't close the underlying fd. + if (stream === process.stdout || stream === process.stderr) { + ret.on('end', () => stream.end()); + } } else { ret = makeAsyncIterable(ret); diff --git a/test/parallel/test-stream-pipeline-process.js b/test/parallel/test-stream-pipeline-process.js new file mode 100644 index 00000000000000..825b4454918ddc --- /dev/null +++ b/test/parallel/test-stream-pipeline-process.js @@ -0,0 +1,29 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const os = require('os'); + +if (process.argv[2] === 'child') { + const { pipeline } = require('stream'); + pipeline( + process.stdin, + process.stdout, + common.mustCall((err) => { + assert.ifError(err); + }) + ); +} else { + const cp = require('child_process'); + cp.exec([ + 'echo', + 'hello', + '|', + `"${process.execPath}"`, + `"${__filename}"`, + 'child' + ].join(' '), common.mustCall((err, stdout) => { + assert.ifError(err); + assert.strictEqual(stdout.split(os.EOL).shift().trim(), 'hello'); + })); +}