Unix and Node: Pipes and Streams

2012-03-08 00:00:00 +0000 by Alex R. Young

An anonymous pipe can be used to connect the standard streams of multiple processes.

tput setaf 48 ; whoami | figlet | tr _ … | tr \\ \` | tr \| ¡ | tr / √

This example prints out the result of whoami using FIGlet, and also uses tput to colourise the output.

Unix pipe example

Pipes are typically denoted with the vertical bar character. Both the | notation and concept of pipes were created by Doug McIlroy, who was quoted in part one of this series for his "Write programs that do one thing and do it well" quote.


Node provides an abstract representation of a stream through the Stream class. It's actually widely used within Node, and represents the Unix text streams we've been discussing very neatly. In fact, it even includes a pipe method:

stream.pipe(destination, [options])

That means we can actually connect the standard input and output like this:

#!/usr/bin/env node


The resume method is called here because standard input is paused by default.

➜ chmod 700 cat.js
➜ echo 'Unix has a funny idea about what a cat is' | ./cat.js
Unix has a funny idea about what a cat is

The nice thing about streams in Node is they work like everything else: they're asynchronous and event-based:

stream.on('data', function(data) {
  console.log('Received data:', data);

Whenever a stream is passed to a readable stream's pipe method, the pipe event will be emitted.


By combining what we've learned in the last few Unix and Node articles, we can start to build command-line tools that resemble real Unix tools. The following example uses Commander.js, which can be installed with npm install commander.

#!/usr/bin/env node

var program = require('commander')
  , c = 90;

  .option('-r, --red', 'Red text')
  .option('-g, --green', 'Green text')
  .option('-b, --blue', 'Blue text')

function colour(c, str) {
  return '\033[' + c + 'm' + str + '\033[0m';

if (program.red) {
  c = 91;
} else if (program.green) {
  c = 92;
} else if (program.blue) {
  c = 94;

process.stdin.on('data', function(data) {
  process.stdout.write(colour(c, data));

Running echo "Some text" | ./colour.js --red will display red text. The expected encoding is set with process.stdin.setEncoding('utf8'), else the data argument passed to the data event on the stdin stream would be a plain buffer. The output is written to stdout using stream.write(string, [encoding], [fd]).


By having such a simple asynchronous API for streams, building Node programs that can work well with pipelines in shell scripts is straightforward. Other methods like stream.pipe are also useful. Read Node's Stream documentation for more details and examples.