From 08432432350ae60aa497b06ea8b18bf05e471881 Mon Sep 17 00:00:00 2001
From: Stefan Legien <stefan@legien.org>
Date: Sat, 27 Feb 2016 21:07:15 +0100
Subject: [PATCH 1/3] Adds head command.

---
 bin/head.js                                |  2 +
 commands.json                              |  3 +-
 dist/commands/head.js                      | 82 +++++++++++++++++++++++++++
 dist/help/head.js                          |  3 +
 packages/head/README.md/template.README.md | 32 +++++++++++
 packages/head/bin/head.js                  |  2 +
 packages/head/bin/parser.js                | 50 +++++++++++++++++
 packages/head/package.json                 | 44 +++++++++++++++
 src/commands/head.js                       | 89 ++++++++++++++++++++++++++++++
 src/help.js                                |  1 +
 src/help/head.js                           |  7 +++
 test/head.js                               | 38 +++++++++++++
 12 files changed, 352 insertions(+), 1 deletion(-)
 create mode 100644 bin/head.js
 create mode 100644 dist/commands/head.js
 create mode 100644 dist/help/head.js
 create mode 100755 packages/head/README.md/template.README.md
 create mode 100644 packages/head/bin/head.js
 create mode 100755 packages/head/bin/parser.js
 create mode 100755 packages/head/package.json
 create mode 100644 src/commands/head.js
 create mode 100644 src/help/head.js
 create mode 100644 test/head.js

diff --git a/bin/head.js b/bin/head.js
new file mode 100644
index 0000000..ceff3d9
--- /dev/null
+++ b/bin/head.js
@@ -0,0 +1,2 @@
+#!/usr/bin/env node
+require('./parser')(process.argv, 'head');
diff --git a/commands.json b/commands.json
index 674cf51..b4b67f2 100755
--- a/commands.json
+++ b/commands.json
@@ -1,10 +1,12 @@
 {
   "commands": [
     "alias",
+    "cat",
     "cd",
     "clear",
     "cp",
     "echo",
+    "head",
     "kill",
     "ls",
     "mkdir",
@@ -12,7 +14,6 @@
     "pwd",
     "sort",
     "touch",
-    "cat",
     "less",
     "grep",
     "rm",
diff --git a/dist/commands/head.js b/dist/commands/head.js
new file mode 100644
index 0000000..ecca3b8
--- /dev/null
+++ b/dist/commands/head.js
@@ -0,0 +1,82 @@
+'use strict';
+
+var interfacer = require('./../util/interfacer');
+var fs = require('fs');
+var fsAutocomplete = require('vorpal-autocomplete-fs');
+
+var head = {
+  exec: function exec(args, options) {
+    var self = this;
+    options = options || {};
+
+    options.argsType = args.stdin === undefined ? 'files' : 'stdin';
+    options.n = options.n === undefined ? 10 : options.n;
+
+    if (options.n < 1) {
+      this.log('Option n must be a positive integer.');
+      return 1;
+    }
+
+    if (options.argsType === 'stdin') {
+      head.readStdin(args.stdin[0], options.n, self);
+    } else {
+      var files = args.files || args;
+      files = files === undefined ? [] : files;
+      files = typeof files === 'string' ? String(files).split(' ') : files;
+      files = files.filter(function (arg) {
+        return String(arg).trim() !== '';
+      });
+      head.readFiles(files, options.n, self);
+    }
+
+    return 0;
+  },
+  readStdin: function readStdin(stdin, numberOfLines, self) {
+    var lines = stdin.split('\n');
+    var linesToRead = numberOfLines >= lines.length ? lines.length : numberOfLines;
+    for (var i = 0; i < linesToRead; i++) {
+      self.log(lines[i]);
+    }
+  },
+  readFiles: function readFiles(files, numberOfLines, self) {
+    var writeHeaders = false;
+    if (files.length > 1) {
+      writeHeaders = true;
+    }
+
+    for (var i = 0; i < files.length; i++) {
+      if (writeHeaders) {
+        head.writeHeader(files[i], i > 0, self);
+      }
+
+      head.readFile(files[i], numberOfLines, self);
+    }
+  },
+  readFile: function readFile(file, numberOfLines, self) {
+    var content = fs.readFileSync(file).toString();
+    var contentArray = content.split('\n');
+    var linesToRead = numberOfLines >= contentArray.length ? contentArray.length : numberOfLines;
+    for (var i = 0; i < linesToRead; i++) {
+      self.log(contentArray[i]);
+    }
+  },
+  writeHeader: function writeHeader(file, includeNewLine, self) {
+    self.log((includeNewLine ? '\n' : '') + '==> ' + file + ' <==\n');
+  }
+};
+
+module.exports = function (vorpal) {
+  if (vorpal === undefined) {
+    return head;
+  }
+  vorpal.api.head = head;
+  vorpal.command('head [files...]').option('-n [number]', 'The first number of lines will be copied to stdout.').autocomplete(fsAutocomplete()).action(function (args, callback) {
+    args.options = args.options || {};
+    return interfacer.call(this, {
+      command: head,
+      args: args,
+      options: args.options,
+      callback: callback
+    });
+  });
+};
\ No newline at end of file
diff --git a/dist/help/head.js b/dist/help/head.js
new file mode 100644
index 0000000..b825824
--- /dev/null
+++ b/dist/help/head.js
@@ -0,0 +1,3 @@
+"use strict";
+
+module.exports = "\nUsage: head [OPTION] [files ...]\nShow first lines of file(s).\n\nReport head bugs to <https://github.com/dthree/cash>\nCash home page: <http://cash.js.org/>\n";
\ No newline at end of file
diff --git a/packages/head/README.md/template.README.md b/packages/head/README.md/template.README.md
new file mode 100755
index 0000000..1a8a2a6
--- /dev/null
+++ b/packages/head/README.md/template.README.md
@@ -0,0 +1,32 @@
+# {package-name}
+
+---
+
+
+This is a cross-platform, 100% ES6 implementation of the Unix `{command-name}` command.
+
+```bash
+npm install {package-name} -g
+```
+
+This will install `{command-name}` globally in your system path.
+
+For help on the command, type:
+
+```bash
+> {command-name} --help
+```
+
+## More
+
+This module is part of [Cash](https://github.com/dthree/cash), a project providing cross-platform implementations of all major Unix-based commands in pure Javascript.
+
+
+## Related
+
+{related}
+
+
+## License
+
+MIT © [David Caccavella](https://github.com/dthree)
diff --git a/packages/head/bin/head.js b/packages/head/bin/head.js
new file mode 100644
index 0000000..ceff3d9
--- /dev/null
+++ b/packages/head/bin/head.js
@@ -0,0 +1,2 @@
+#!/usr/bin/env node
+require('./parser')(process.argv, 'head');
diff --git a/packages/head/bin/parser.js b/packages/head/bin/parser.js
new file mode 100755
index 0000000..df2a466
--- /dev/null
+++ b/packages/head/bin/parser.js
@@ -0,0 +1,50 @@
+'use strict';
+
+module.exports = function (args, command) {
+  args.splice(0, 2);
+  var pipes = (args.indexOf('|') > -1);
+  if (args.length === 0) {
+    // If we don't have to parse arguments, do
+    // the quickest load: just the raw js file
+    // of the command and nothing else.
+    var cmd = require('./../dist/commands/' + command)();
+    cmd.exec.call(console, {options: {}}, {});
+  } else if (pipes === false) {
+    // If we need to parse args for this
+    // command only, pull up vorpal and just load
+    // that one command.
+    var vorpal = require('vorpal')();
+    vorpal.api = {};
+    require('./../dist/commands/' + command)(vorpal);
+    args = args.join(' ');
+
+    // If we passed in a help request, load in
+    // the help file.
+    if (args.indexOf('help') > -1 || args.indexOf('?') > -1) {
+      let help;
+      try {
+        help = require('./../dist/help/' + command + '.js');
+        help = String(help).replace(/^\n|\n$/g, '');
+      } catch (e) {}
+      let cmdObj = vorpal.find(command);
+      if (cmdObj && help) {
+        cmdObj.help(function (argus, cb) {
+          cb(help);
+        })
+      }
+    }
+    vorpal.exec(command + ' ' + args);
+  } else {
+    // If we get into piping other commands,
+    // we need to go full bore and load the
+    // entire cash library.
+    // I guess we could technically parse all
+    // of the passed args, look for applicable
+    // commands and only load those, but that's
+    // some messy work for something that might
+    // not matter. If you're reading this and
+    // have deemed it matters, do a PR.
+    var cash = require('./../dist/index');
+    cash.vorpal.exec(command + ' ' + args.join(' '));
+  }
+};
diff --git a/packages/head/package.json b/packages/head/package.json
new file mode 100755
index 0000000..4778efe
--- /dev/null
+++ b/packages/head/package.json
@@ -0,0 +1,44 @@
+{
+  "name": "",
+  "version": "0.0.1",
+  "description": "",
+  "main": "",
+  "scripts": {},
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/dthree/cash.git"
+  },
+  "keywords": [
+    "cash",
+    "terminal",
+    "emulator",
+    "cygwin",
+    "cli",
+    "windows",
+    "linux",
+    "unix",
+    "posix",
+    "bash",
+    "tty",
+    "util",
+    "vorpal",
+    "vorpal.js"
+  ],
+  "author": "dthree",
+  "license": "MIT",
+  "bugs": {
+    "url": "https://github.com/dthree/cash/issues"
+  },
+  "homepage": "https://github.com/dthree/cash#readme",
+  "devDependencies": {},
+  "bin": {},
+  "dependencies": {},
+  "engines": {
+    "node": ">= 4",
+    "iojs": ">= 1.0.0"
+  },
+  "files": [
+    "dist",
+    "bin"
+  ]
+}
\ No newline at end of file
diff --git a/src/commands/head.js b/src/commands/head.js
new file mode 100644
index 0000000..1f652c8
--- /dev/null
+++ b/src/commands/head.js
@@ -0,0 +1,89 @@
+'use strict';
+
+const interfacer = require('./../util/interfacer');
+const fs = require('fs');
+const fsAutocomplete = require('vorpal-autocomplete-fs');
+
+const head = {
+
+  exec(args, options) {
+    const self = this;
+    options = options || {};
+
+    options.argsType = args.stdin === undefined ? 'files' : 'stdin';
+    options.n = options.n === undefined ? 10 : options.n;
+
+    if (options.n < 1) {
+      this.log('Option n must be a positive integer.');
+      return 1;
+    }
+
+    if (options.argsType === 'stdin') {
+      head.readStdin(args.stdin[0], options.n, self);
+    } else {
+      let files = args.files || args;
+      files = (files === undefined) ? [] : files;
+      files = (typeof files === 'string') ? String(files).split(' ') : files;
+      files = files.filter(arg => String(arg).trim() !== '');
+      head.readFiles(files, options.n, self);
+    }
+
+    return 0;
+  },
+
+  readStdin(stdin, numberOfLines, self) {
+    const lines = stdin.split('\n');
+    const linesToRead = numberOfLines >= lines.length ? lines.length : numberOfLines;
+    for (let i = 0; i < linesToRead; i++) {
+      self.log(lines[i]);
+    }
+  },
+
+  readFiles(files, numberOfLines, self) {
+    let writeHeaders = false;
+    if (files.length > 1) {
+      writeHeaders = true;
+    }
+
+    for (let i = 0; i < files.length; i++) {
+      if (writeHeaders) {
+        head.writeHeader(files[i], i > 0, self);
+      }
+
+      head.readFile(files[i], numberOfLines, self);
+    }
+  },
+
+  readFile(file, numberOfLines, self) {
+    const content = fs.readFileSync(file).toString();
+    const contentArray = content.split('\n');
+    const linesToRead = numberOfLines >= contentArray.length ? contentArray.length : numberOfLines;
+    for (let i = 0; i < linesToRead; i++) {
+      self.log(contentArray[i]);
+    }
+  },
+
+  writeHeader(file, includeNewLine, self) {
+    self.log(`${includeNewLine ? '\n' : ''}==> ${file} <==\n`);
+  }
+};
+
+module.exports = function (vorpal) {
+  if (vorpal === undefined) {
+    return head;
+  }
+  vorpal.api.head = head;
+  vorpal
+      .command('head [files...]')
+      .option('-n [number]', 'The first number of lines will be copied to stdout.')
+      .autocomplete(fsAutocomplete())
+      .action(function (args, callback) {
+        args.options = args.options || {};
+        return interfacer.call(this, {
+          command: head,
+          args,
+          options: args.options,
+          callback
+        });
+      });
+};
diff --git a/src/help.js b/src/help.js
index 5d29db4..673f5ed 100755
--- a/src/help.js
+++ b/src/help.js
@@ -10,6 +10,7 @@ const commands = [
   'cp [-fnr] source ... dest',
   'echo [eE] [arg ...]',
   'grep [-bHhinqsvw] [-m max] [--silent] [--include pattern] pattern [files ...]',
+  'head [-n number] [files...]',
   'kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l',
   'less [files ...]',
   'ls [-aAdFhilQrRStUwx1] [paths ...]',
diff --git a/src/help/head.js b/src/help/head.js
new file mode 100644
index 0000000..478ff3d
--- /dev/null
+++ b/src/help/head.js
@@ -0,0 +1,7 @@
+module.exports = `
+Usage: head [OPTION] [files ...]
+Show first lines of file(s).
+
+Report head bugs to <https://github.com/dthree/cash>
+Cash home page: <http://cash.js.org/>
+`;
diff --git a/test/head.js b/test/head.js
new file mode 100644
index 0000000..c3df465
--- /dev/null
+++ b/test/head.js
@@ -0,0 +1,38 @@
+'use strict';
+
+require('assert');
+require('mocha');
+const should = require('should');
+const cash = require('../dist/index.js');
+const $ = require('shelljs');
+require('shelljs/global');
+
+describe('head', function () {
+  before(function () {
+    'line1\nline2\nline3\nline4\nline5\nline6\nline7\nline8\nline9\nline10\nline11'.to('eleven.test');
+    'line1\nline2\nline3\nline4\nline5\nline6\nline7\nline8\nline9\nline10'.to('ten.test');
+  });
+
+  after(function () {
+    $.rm(['eleven.test', 'ten.test']);
+  });
+
+  it('should exist and be a function', function () {
+    should.exist(cash.head);
+  });
+
+  it('should give back ten lines when called without options', function () {
+    const result = cash.head('eleven.test');
+    result.should.be.equal('line1\nline2\nline3\nline4\nline5\nline6\nline7\nline8\nline9\nline10\n');
+  });
+
+  it('should give back five lines when called with option n set to 5', function () {
+    const result = cash.head('eleven.test', {n: 5});
+    result.should.be.equal('line1\nline2\nline3\nline4\nline5\n');
+  });
+
+  it('should write header when used with more than one file', function () {
+    const result = cash.head(['eleven.test', 'ten.test'], {n: 2});
+    result.should.be.equal('==> eleven.test <==\n\nline1\nline2\n\n==> ten.test <==\n\nline1\nline2\n');
+  });
+});

From 1436d5b2aa4732ade96b061202b0a15b1c1caea1 Mon Sep 17 00:00:00 2001
From: Stefan Legien <stefan@legien.org>
Date: Wed, 2 Mar 2016 11:22:04 +0100
Subject: [PATCH 2/3] Modified cat and head for better 'pipeability'.

---
 dist/commands/cat.js              |  5 ++-
 dist/commands/head.js             | 64 ++++++++++++++++++++++-----------------
 packages/cat/dist/commands/cat.js |  5 ++-
 src/commands/cat.js               | 53 +++++++++++++++++---------------
 src/commands/head.js              | 59 +++++++++++++++++++-----------------
 test/head.js                      |  2 +-
 6 files changed, 105 insertions(+), 83 deletions(-)

diff --git a/dist/commands/cat.js b/dist/commands/cat.js
index 4ed1950..b6af1d2 100755
--- a/dist/commands/cat.js
+++ b/dist/commands/cat.js
@@ -83,10 +83,13 @@ var cat = {
           // If -E, append a $ to each line end.
           var dollarStr = options.showends ? '$' : '';
           var line = numStr + parts[j] + dollarStr;
-          self.log(line);
           stdout += line + '\n';
         }
       }
+
+      if (stdout.length > 0) {
+        self.log(stdout.slice(0, stdout.length - 1));
+      }
       return 0;
     } catch (e) {
       /* istanbul ignore next */
diff --git a/dist/commands/head.js b/dist/commands/head.js
index ecca3b8..54fe002 100644
--- a/dist/commands/head.js
+++ b/dist/commands/head.js
@@ -13,55 +13,63 @@ var head = {
     options.n = options.n === undefined ? 10 : options.n;
 
     if (options.n < 1) {
-      this.log('Option n must be a positive integer.');
+      self.log('Option n must be a positive integer.');
       return 1;
     }
 
     if (options.argsType === 'stdin') {
-      head.readStdin(args.stdin[0], options.n, self);
-    } else {
-      var files = args.files || args;
-      files = files === undefined ? [] : files;
-      files = typeof files === 'string' ? String(files).split(' ') : files;
-      files = files.filter(function (arg) {
-        return String(arg).trim() !== '';
-      });
-      head.readFiles(files, options.n, self);
+      self.log(head.readLines(args.stdin[0], options.n));
+      return 0;
     }
 
-    return 0;
-  },
-  readStdin: function readStdin(stdin, numberOfLines, self) {
-    var lines = stdin.split('\n');
-    var linesToRead = numberOfLines >= lines.length ? lines.length : numberOfLines;
-    for (var i = 0; i < linesToRead; i++) {
-      self.log(lines[i]);
-    }
-  },
-  readFiles: function readFiles(files, numberOfLines, self) {
+    var files = args.files || args;
+    files = files === undefined ? [] : files;
+    files = typeof files === 'string' ? String(files).split(' ') : files;
+    files = files.filter(function (arg) {
+      return String(arg).trim() !== '';
+    });
+
+    var stdout = '';
     var writeHeaders = false;
     if (files.length > 1) {
       writeHeaders = true;
     }
 
+    var content = [];
+    for (var i = 0; i < files.length; i++) {
+      try {
+        content[i] = fs.readFileSync(files[i]).toString();
+      } catch (e) {
+        self.log('head: ' + files[i] + ': No such file or directory');
+        return 1;
+      }
+    }
+
     for (var i = 0; i < files.length; i++) {
       if (writeHeaders) {
-        head.writeHeader(files[i], i > 0, self);
+        stdout += (i > 0 ? '\n\n' : '') + '==> ' + files[i] + ' <==\n';
       }
 
-      head.readFile(files[i], numberOfLines, self);
+      stdout += head.readLines(content[i], options.n);
     }
+
+    self.log(stdout);
+    return 0;
   },
-  readFile: function readFile(file, numberOfLines, self) {
-    var content = fs.readFileSync(file).toString();
+  readLines: function readLines(content, numberOfLines) {
+    var stdout = '';
     var contentArray = content.split('\n');
     var linesToRead = numberOfLines >= contentArray.length ? contentArray.length : numberOfLines;
     for (var i = 0; i < linesToRead; i++) {
-      self.log(contentArray[i]);
+      if (stdout === '') {
+        stdout = contentArray[i];
+        continue;
+      }
+
+      stdout += '\n' + contentArray[i];
     }
-  },
-  writeHeader: function writeHeader(file, includeNewLine, self) {
-    self.log((includeNewLine ? '\n' : '') + '==> ' + file + ' <==\n');
+
+    return stdout;
   }
 };
 
diff --git a/packages/cat/dist/commands/cat.js b/packages/cat/dist/commands/cat.js
index 4ed1950..b6af1d2 100755
--- a/packages/cat/dist/commands/cat.js
+++ b/packages/cat/dist/commands/cat.js
@@ -83,10 +83,13 @@ var cat = {
           // If -E, append a $ to each line end.
           var dollarStr = options.showends ? '$' : '';
           var line = numStr + parts[j] + dollarStr;
-          self.log(line);
           stdout += line + '\n';
         }
       }
+
+      if (stdout.length > 0) {
+        self.log(stdout.slice(0, stdout.length - 1));
+      }
       return 0;
     } catch (e) {
       /* istanbul ignore next */
diff --git a/src/commands/cat.js b/src/commands/cat.js
index edce1a7..a1c61e3 100755
--- a/src/commands/cat.js
+++ b/src/commands/cat.js
@@ -81,18 +81,21 @@ const cat = {
             ctr++;
           }
           const numStr = (numbered) ?
-            `${lpad(String(ctr), 6, ' ')}  ` :
-            '';
+              `${lpad(String(ctr), 6, ' ')}  ` :
+              '';
           // If -E, append a $ to each line end.
           const dollarStr = (options.showends) ? '$' : '';
           const line =
-            numStr +
-            parts[j] +
-            dollarStr;
-          self.log(line);
+              numStr +
+              parts[j] +
+              dollarStr;
           stdout += `${line}\n`;
         }
       }
+
+      if (stdout.length > 0) {
+        self.log(stdout.slice(0, stdout.length - 1));
+      }
       return 0;
     } catch (e) {
       /* istanbul ignore next */
@@ -109,24 +112,24 @@ module.exports = function (vorpal) {
   }
   vorpal.api.cat = cat;
   vorpal
-    .command('cat [files...]')
-    .option('-A, --show-all', 'equivalent to -vET')
-    .option('-b, --number-nonblank', 'number nonempty output lines, overrides -n')
-    .option('-e', 'equivalent to -vE')
-    .option('-E, --show-ends', 'display $ at end of each line')
-    .option('-n, --number', 'number all output lines')
-    .option('-s, --squeeze-blank', 'suppress repeated empty output lines')
-    .option('-t', 'equivalent to -vT')
-    .option('-T, --show-tabs', 'display TAB characters as ^I')
-    .option('-v, --show-nonprinting', 'use ^ and M- notation, except for LFD and TAB') // this doesn't work yet...
-    .autocomplete(fsAutocomplete())
-    .action(function (args, cb) {
-      args.options = args.options || {};
-      return interfacer.call(this, {
-        command: cat,
-        args,
-        options: args.options,
-        callback: cb
+      .command('cat [files...]')
+      .option('-A, --show-all', 'equivalent to -vET')
+      .option('-b, --number-nonblank', 'number nonempty output lines, overrides -n')
+      .option('-e', 'equivalent to -vE')
+      .option('-E, --show-ends', 'display $ at end of each line')
+      .option('-n, --number', 'number all output lines')
+      .option('-s, --squeeze-blank', 'suppress repeated empty output lines')
+      .option('-t', 'equivalent to -vT')
+      .option('-T, --show-tabs', 'display TAB characters as ^I')
+      .option('-v, --show-nonprinting', 'use ^ and M- notation, except for LFD and TAB') // this doesn't work yet...
+      .autocomplete(fsAutocomplete())
+      .action(function (args, cb) {
+        args.options = args.options || {};
+        return interfacer.call(this, {
+          command: cat,
+          args,
+          options: args.options,
+          callback: cb
+        });
       });
-    });
 };
diff --git a/src/commands/head.js b/src/commands/head.js
index 1f652c8..ac97fc2 100644
--- a/src/commands/head.js
+++ b/src/commands/head.js
@@ -14,57 +14,62 @@ const head = {
     options.n = options.n === undefined ? 10 : options.n;
 
     if (options.n < 1) {
-      this.log('Option n must be a positive integer.');
+      self.log('Option n must be a positive integer.');
       return 1;
     }
 
     if (options.argsType === 'stdin') {
-      head.readStdin(args.stdin[0], options.n, self);
-    } else {
-      let files = args.files || args;
-      files = (files === undefined) ? [] : files;
-      files = (typeof files === 'string') ? String(files).split(' ') : files;
-      files = files.filter(arg => String(arg).trim() !== '');
-      head.readFiles(files, options.n, self);
+      self.log(head.readLines(args.stdin[0], options.n));
+      return 0;
     }
 
-    return 0;
-  },
-
-  readStdin(stdin, numberOfLines, self) {
-    const lines = stdin.split('\n');
-    const linesToRead = numberOfLines >= lines.length ? lines.length : numberOfLines;
-    for (let i = 0; i < linesToRead; i++) {
-      self.log(lines[i]);
-    }
-  },
+    let files = args.files || args;
+    files = (files === undefined) ? [] : files;
+    files = (typeof files === 'string') ? String(files).split(' ') : files;
+    files = files.filter(arg => String(arg).trim() !== '');
 
-  readFiles(files, numberOfLines, self) {
+    let stdout = '';
     let writeHeaders = false;
     if (files.length > 1) {
       writeHeaders = true;
     }
 
+    const content = [];
+    for (let i = 0; i < files.length; i++) {
+      try {
+        content[i] = fs.readFileSync(files[i]).toString();
+      } catch (e) {
+        self.log(`head: ${files[i]}: No such file or directory`);
+        return 1;
+      }
+    }
+
     for (let i = 0; i < files.length; i++) {
       if (writeHeaders) {
-        head.writeHeader(files[i], i > 0, self);
+        stdout += `${i > 0 ? '\n\n' : ''}==> ${files[i]} <==\n`;
       }
 
-      head.readFile(files[i], numberOfLines, self);
+      stdout += head.readLines(content[i], options.n);
     }
+
+    self.log(stdout);
+    return 0;
   },
 
-  readFile(file, numberOfLines, self) {
-    const content = fs.readFileSync(file).toString();
+  readLines(content, numberOfLines) {
+    let stdout = '';
     const contentArray = content.split('\n');
     const linesToRead = numberOfLines >= contentArray.length ? contentArray.length : numberOfLines;
     for (let i = 0; i < linesToRead; i++) {
-      self.log(contentArray[i]);
+      if (stdout === '') {
+        stdout = contentArray[i];
+        continue;
+      }
+
+      stdout += `\n${contentArray[i]}`;
     }
-  },
 
-  writeHeader(file, includeNewLine, self) {
-    self.log(`${includeNewLine ? '\n' : ''}==> ${file} <==\n`);
+    return stdout;
   }
 };
 
diff --git a/test/head.js b/test/head.js
index c3df465..724191f 100644
--- a/test/head.js
+++ b/test/head.js
@@ -33,6 +33,6 @@ describe('head', function () {
 
   it('should write header when used with more than one file', function () {
     const result = cash.head(['eleven.test', 'ten.test'], {n: 2});
-    result.should.be.equal('==> eleven.test <==\n\nline1\nline2\n\n==> ten.test <==\n\nline1\nline2\n');
+    result.should.be.equal('==> eleven.test <==\nline1\nline2\n\n==> ten.test <==\nline1\nline2\n');
   });
 });

From e60b7ab37205efee42b23ded80668c9253eac63a Mon Sep 17 00:00:00 2001
From: Stefan Legien <stefan@legien.org>
Date: Wed, 2 Mar 2016 13:30:15 +0100
Subject: [PATCH 3/3] Removed second cat.

---
 commands.json | 1 -
 1 file changed, 1 deletion(-)

diff --git a/commands.json b/commands.json
index 6bf6388..c4b618b 100755
--- a/commands.json
+++ b/commands.json
@@ -17,7 +17,6 @@
     "sort",
     "touch",
     "true",
-    "cat",
     "less",
     "grep",
     "rm",
