How to detect if a Node.js script is running through a shell pipe? How to detect if a Node.js script is running through a shell pipe? node.js node.js

How to detect if a Node.js script is running through a shell pipe?


I just found out a simpler answer to part of my question.

To quickly and synchronously detect if piped content is being passed to the current script in Node.js, use the process.stdin.isTTY boolean:

$ node -p -e 'process.stdin.isTTY'true$ echo 'foo' | node -p -e 'process.stdin.isTTY'undefined

So, in a script, you could do something like this:

if (process.stdin.isTTY) {  // handle shell arguments} else {  // handle piped content (see Jerome’s answer)}

The reason I didn’t find this before is because I was looking at the documentation for process, where isTTY is not mentioned at all. Instead, it’s mentioned in the TTY documentation.


Pipes are made to handle small inputs like "foo bar" but also huge files.

The stream API makes sure that you can start handling data without waiting for the huge file to be totally piped through (this is better for speed & memory). The way it does this is by giving you chunks of data.

There is no synchronous API for pipes. If you really want to have the whole piped input in your hands before doing something, you can use

note: use only node >= 0.10.0 because the example uses the stream2 API

var data = '';function withPipe(data) {   console.log('content was piped');   console.log(data.trim());}function withoutPipe() {   console.log('no content was piped');}var self = process.stdin;self.on('readable', function() {    var chunk = this.read();    if (chunk === null) {        withoutPipe();    } else {       data += chunk;    }});self.on('end', function() {   withPipe(data);});

test with

echo "foo bar" | node test.js

and

node test.js


It turns out that process.stdin.isTTY is not reliable because you can spawn a child process that is not a TTY.

I found a better solution here using file descriptors.

You can test to see if your program with piped in or out with these functions:

function pipedIn(cb) {    fs.fstat(0, function(err, stats) {        if (err) {            cb(err)        } else {            cb(null, stats.isFIFO())        }    })}function pipedOut(cb) {    fs.fstat(1, function(err, stats) {        if (err) {            cb(err)        } else {            cb(null, stats.isFIFO())        }    })}pipedIn((err, x) => console.log("in", x))pipedOut((err, x) => console.log("out", x))

Here's some tests demonstrating that it works.

❯❯❯ node pipes.jsin falseout false❯❯❯ node pipes.js | cat -in falseout true❯❯❯ echo 'hello' | node pipes.js | cat -in trueout true❯❯❯ echo 'hello' | node pipes.jsin trueout false❯❯❯ node -p -e "let x = require('child_process').exec(\"node pipes.js\", (err, res) => console.log(res))"undefinedin falseout false❯❯❯ node -p -e "let x = require('child_process').exec(\"echo 'hello' | node pipes.js\", (err, res) => console.log(res))"undefinedin trueout false❯❯❯ node -p -e "let x = require('child_process').exec(\"echo 'hello' | node pipes.js | cat -\", (err, res) => console.log(res))"undefinedin trueout true❯❯❯ node -p -e "let x = require('child_process').exec(\"node pipes.js | cat -\", (err, res) => console.log(res))"undefinedin falseout true