mirror of
https://github.com/shelljs/shelljs.git
synced 2026-02-01 16:56:47 +00:00
Merge pull request #379 from shelljs/feat-head-sort-commands
New commands: sort(), head(), and tail()
This commit is contained in:
commit
2984b40b12
48
README.md
48
README.md
@ -302,6 +302,36 @@ containing the files if more than one file is given (a new line character is
|
||||
introduced between each file).
|
||||
|
||||
|
||||
### head([{'-n', \<num\>},] file [, file ...])
|
||||
### head([{'-n', \<num\>},] file_array)
|
||||
|
||||
Examples:
|
||||
|
||||
```javascript
|
||||
var str = head({'-n', 1}, 'file*.txt');
|
||||
var str = head('file1', 'file2');
|
||||
var str = head(['file1', 'file2']); // same as above
|
||||
```
|
||||
|
||||
Output the first 10 lines of a file (or the first `<num>` if `-n` is
|
||||
specified)
|
||||
|
||||
|
||||
### tail([{'-n', \<num\>},] file [, file ...])
|
||||
### tail([{'-n', \<num\>},] file_array)
|
||||
|
||||
Examples:
|
||||
|
||||
```javascript
|
||||
var str = tail({'-n', 1}, 'file*.txt');
|
||||
var str = tail('file1', 'file2');
|
||||
var str = tail(['file1', 'file2']); // same as above
|
||||
```
|
||||
|
||||
Output the last 10 lines of a file (or the last `<num>` if `-n` is
|
||||
specified)
|
||||
|
||||
|
||||
### ShellString.prototype.to(file)
|
||||
|
||||
Examples:
|
||||
@ -344,6 +374,24 @@ Reads an input string from `files` and performs a JavaScript `replace()` on the
|
||||
using the given search regex and replacement string or function. Returns the new string after replacement.
|
||||
|
||||
|
||||
### sort([options,] file [, file ...])
|
||||
### sort([options,] file_array)
|
||||
Available options:
|
||||
|
||||
+ `-r`: Reverse the result of comparisons
|
||||
+ `-n`: Compare according to numerical value
|
||||
|
||||
Examples:
|
||||
|
||||
```javascript
|
||||
sort('foo.txt', 'bar.txt');
|
||||
sort('-r', 'foo.txt');
|
||||
```
|
||||
|
||||
Return the contents of the files, sorted line-by-line. Sorting multiple
|
||||
files mixes their content, just like unix sort does.
|
||||
|
||||
|
||||
### grep([options,] regex_filter, file [, file ...])
|
||||
### grep([options,] regex_filter, file_array)
|
||||
Available options:
|
||||
|
||||
12
shell.js
12
shell.js
@ -58,6 +58,14 @@ exports.test = common.wrap('test', _test);
|
||||
var _cat = require('./src/cat');
|
||||
exports.cat = common.wrap('cat', _cat, {idx: 1});
|
||||
|
||||
//@include ./src/head
|
||||
var _head = require('./src/head');
|
||||
exports.head = common.wrap('head', _head, {idx: 1});
|
||||
|
||||
//@include ./src/tail
|
||||
var _tail = require('./src/tail');
|
||||
exports.tail = common.wrap('tail', _tail, {idx: 1});
|
||||
|
||||
// The below commands have been moved to common.ShellString(), and are only here
|
||||
// for generating the docs
|
||||
//@include ./src/to
|
||||
@ -67,6 +75,10 @@ exports.cat = common.wrap('cat', _cat, {idx: 1});
|
||||
var _sed = require('./src/sed');
|
||||
exports.sed = common.wrap('sed', _sed, {idx: 3});
|
||||
|
||||
//@include ./src/sort
|
||||
var _sort = require('./src/sort');
|
||||
exports.sort = common.wrap('sort', _sort, {idx: 1});
|
||||
|
||||
//@include ./src/grep
|
||||
var _grep = require('./src/grep');
|
||||
exports.grep = common.wrap('grep', _grep, {idx: 2});
|
||||
|
||||
@ -101,7 +101,7 @@ var ShellString = function (stdout, stderr, code) {
|
||||
that.code = code;
|
||||
that.to = function() {wrap('to', _to, {idx: 1}).apply(that.stdout, arguments); return that;};
|
||||
that.toEnd = function() {wrap('toEnd', _toEnd, {idx: 1}).apply(that.stdout, arguments); return that;};
|
||||
['cat', 'sed', 'grep', 'exec'].forEach(function (cmd) {
|
||||
['cat', 'head', 'sed', 'sort', 'tail', 'grep', 'exec'].forEach(function (cmd) {
|
||||
that[cmd] = function() {return shell[cmd].apply(that.stdout, arguments);};
|
||||
});
|
||||
return that;
|
||||
|
||||
96
src/head.js
Normal file
96
src/head.js
Normal file
@ -0,0 +1,96 @@
|
||||
var common = require('./common');
|
||||
var fs = require('fs');
|
||||
|
||||
// This reads n or more lines, or the entire file, whichever is less.
|
||||
function readSomeLines(file, numLines) {
|
||||
var BUF_LENGTH = 64*1024,
|
||||
buf = new Buffer(BUF_LENGTH),
|
||||
bytesRead = BUF_LENGTH,
|
||||
pos = 0,
|
||||
fdr = null;
|
||||
|
||||
try {
|
||||
fdr = fs.openSync(file, 'r');
|
||||
} catch(e) {
|
||||
common.error('cannot read file: ' + file);
|
||||
}
|
||||
|
||||
var numLinesRead = 0;
|
||||
var ret = '';
|
||||
while (bytesRead === BUF_LENGTH && numLinesRead < numLines) {
|
||||
bytesRead = fs.readSync(fdr, buf, 0, BUF_LENGTH, pos);
|
||||
var bufStr = buf.toString('utf8', 0, bytesRead);
|
||||
numLinesRead += bufStr.split('\n').length - 1;
|
||||
ret += bufStr;
|
||||
pos += bytesRead;
|
||||
}
|
||||
|
||||
fs.closeSync(fdr);
|
||||
return ret;
|
||||
}
|
||||
//@
|
||||
//@ ### head([{'-n', \<num\>},] file [, file ...])
|
||||
//@ ### head([{'-n', \<num\>},] file_array)
|
||||
//@
|
||||
//@ Examples:
|
||||
//@
|
||||
//@ ```javascript
|
||||
//@ var str = head({'-n', 1}, 'file*.txt');
|
||||
//@ var str = head('file1', 'file2');
|
||||
//@ var str = head(['file1', 'file2']); // same as above
|
||||
//@ ```
|
||||
//@
|
||||
//@ Output the first 10 lines of a file (or the first `<num>` if `-n` is
|
||||
//@ specified)
|
||||
function _head(options, files) {
|
||||
options = common.parseOptions(options, {
|
||||
'n': 'numLines'
|
||||
});
|
||||
var head = [];
|
||||
var pipe = common.readFromPipe(this);
|
||||
|
||||
if (!files && !pipe)
|
||||
common.error('no paths given');
|
||||
|
||||
var idx = 1;
|
||||
if (options.numLines === true) {
|
||||
idx = 2;
|
||||
options.numLines = Number(arguments[1]);
|
||||
} else if (options.numLines === false) {
|
||||
options.numLines = 10;
|
||||
}
|
||||
files = [].slice.call(arguments, idx);
|
||||
|
||||
if (pipe)
|
||||
files.unshift('-');
|
||||
|
||||
var shouldAppendNewline = false;
|
||||
files.forEach(function(file) {
|
||||
if (!fs.existsSync(file) && file !== '-') {
|
||||
common.error('no such file or directory: ' + file, true);
|
||||
return;
|
||||
}
|
||||
|
||||
var contents;
|
||||
if (file === '-')
|
||||
contents = pipe;
|
||||
else if (options.numLines < 0) {
|
||||
contents = fs.readFileSync(file, 'utf8');
|
||||
} else {
|
||||
contents = readSomeLines(file, options.numLines);
|
||||
}
|
||||
|
||||
var lines = contents.split('\n');
|
||||
var hasTrailingNewline = (lines[lines.length-1] === '');
|
||||
if (hasTrailingNewline)
|
||||
lines.pop();
|
||||
shouldAppendNewline = (hasTrailingNewline || options.numLines < lines.length);
|
||||
|
||||
head = head.concat(lines.slice(0, options.numLines));
|
||||
});
|
||||
|
||||
if (shouldAppendNewline)
|
||||
head.push(''); // to add a trailing newline once we join
|
||||
return new common.ShellString(head.join('\n'), common.state.error, common.state.errorCode);
|
||||
}
|
||||
module.exports = _head;
|
||||
87
src/sort.js
Normal file
87
src/sort.js
Normal file
@ -0,0 +1,87 @@
|
||||
var common = require('./common');
|
||||
var fs = require('fs');
|
||||
|
||||
// parse out the number prefix of a line
|
||||
function parseNumber (str) {
|
||||
var match = str.match(/^\s*(\d*)\s*(.*)$/);
|
||||
return {num: Number(match[1]), value: match[2]};
|
||||
}
|
||||
|
||||
// compare two strings case-insensitively, but examine case for strings that are
|
||||
// case-insensitive equivalent
|
||||
function unixCmp(a, b) {
|
||||
var aLower = a.toLowerCase();
|
||||
var bLower = b.toLowerCase();
|
||||
return (aLower === bLower ?
|
||||
-1 * a.localeCompare(b) : // unix sort treats case opposite how javascript does
|
||||
aLower.localeCompare(bLower));
|
||||
}
|
||||
|
||||
// compare two strings in the fashion that unix sort's -n option works
|
||||
function numericalCmp(a, b) {
|
||||
var objA = parseNumber(a);
|
||||
var objB = parseNumber(b);
|
||||
if (objA.hasOwnProperty('num') && objB.hasOwnProperty('num')) {
|
||||
return ((objA.num !== objB.num) ?
|
||||
(objA.num - objB.num) :
|
||||
unixCmp(objA.value, objB.value));
|
||||
} else {
|
||||
return unixCmp(objA.value, objB.value);
|
||||
}
|
||||
}
|
||||
|
||||
//@
|
||||
//@ ### sort([options,] file [, file ...])
|
||||
//@ ### sort([options,] file_array)
|
||||
//@ Available options:
|
||||
//@
|
||||
//@ + `-r`: Reverse the result of comparisons
|
||||
//@ + `-n`: Compare according to numerical value
|
||||
//@
|
||||
//@ Examples:
|
||||
//@
|
||||
//@ ```javascript
|
||||
//@ sort('foo.txt', 'bar.txt');
|
||||
//@ sort('-r', 'foo.txt');
|
||||
//@ ```
|
||||
//@
|
||||
//@ Return the contents of the files, sorted line-by-line. Sorting multiple
|
||||
//@ files mixes their content, just like unix sort does.
|
||||
function _sort(options, files) {
|
||||
options = common.parseOptions(options, {
|
||||
'r': 'reverse',
|
||||
'n': 'numerical'
|
||||
});
|
||||
|
||||
// Check if this is coming from a pipe
|
||||
var pipe = common.readFromPipe(this);
|
||||
|
||||
if (!files && !pipe)
|
||||
common.error('no files given');
|
||||
|
||||
files = [].slice.call(arguments, 1);
|
||||
|
||||
if (pipe)
|
||||
files.unshift('-');
|
||||
|
||||
var lines = [];
|
||||
files.forEach(function(file) {
|
||||
if (!fs.existsSync(file) && file !== '-') {
|
||||
// exit upon any sort of error
|
||||
common.error('no such file or directory: ' + file);
|
||||
}
|
||||
|
||||
var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8');
|
||||
lines = lines.concat(contents.trimRight().split(/\r*\n/));
|
||||
});
|
||||
|
||||
var sorted;
|
||||
sorted = lines.sort(options.numerical ? numericalCmp : unixCmp);
|
||||
|
||||
if (options.reverse)
|
||||
sorted = sorted.reverse();
|
||||
|
||||
return new common.ShellString(sorted.join('\n')+'\n', common.state.error, common.state.errorCode);
|
||||
}
|
||||
|
||||
module.exports = _sort;
|
||||
65
src/tail.js
Normal file
65
src/tail.js
Normal file
@ -0,0 +1,65 @@
|
||||
var common = require('./common');
|
||||
var fs = require('fs');
|
||||
|
||||
//@
|
||||
//@ ### tail([{'-n', \<num\>},] file [, file ...])
|
||||
//@ ### tail([{'-n', \<num\>},] file_array)
|
||||
//@
|
||||
//@ Examples:
|
||||
//@
|
||||
//@ ```javascript
|
||||
//@ var str = tail({'-n', 1}, 'file*.txt');
|
||||
//@ var str = tail('file1', 'file2');
|
||||
//@ var str = tail(['file1', 'file2']); // same as above
|
||||
//@ ```
|
||||
//@
|
||||
//@ Output the last 10 lines of a file (or the last `<num>` if `-n` is
|
||||
//@ specified)
|
||||
function _tail(options, files) {
|
||||
options = common.parseOptions(options, {
|
||||
'n': 'numLines'
|
||||
});
|
||||
var tail = [];
|
||||
var pipe = common.readFromPipe(this);
|
||||
|
||||
if (!files && !pipe)
|
||||
common.error('no paths given');
|
||||
|
||||
var idx = 1;
|
||||
if (options.numLines === true) {
|
||||
idx = 2;
|
||||
options.numLines = Number(arguments[1]);
|
||||
} else if (options.numLines === false) {
|
||||
options.numLines = 10;
|
||||
}
|
||||
options.numLines = -1 * Math.abs(options.numLines);
|
||||
files = [].slice.call(arguments, idx);
|
||||
|
||||
if (pipe)
|
||||
files.unshift('-');
|
||||
|
||||
var shouldAppendNewline = false;
|
||||
files.forEach(function(file) {
|
||||
if (!fs.existsSync(file) && file !== '-') {
|
||||
common.error('no such file or directory: ' + file, true);
|
||||
return;
|
||||
}
|
||||
|
||||
var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8');
|
||||
|
||||
var lines = contents.split('\n');
|
||||
if (lines[lines.length-1] === '') {
|
||||
lines.pop();
|
||||
shouldAppendNewline = true;
|
||||
} else {
|
||||
shouldAppendNewline = false;
|
||||
}
|
||||
|
||||
tail = tail.concat(lines.slice(options.numLines));
|
||||
});
|
||||
|
||||
if (shouldAppendNewline)
|
||||
tail.push(''); // to add a trailing newline once we join
|
||||
return new common.ShellString(tail.join('\n'), common.state.error, common.state.errorCode);
|
||||
}
|
||||
module.exports = _tail;
|
||||
@ -52,10 +52,11 @@ child.exec(JSON.stringify(process.execPath)+' '+file, function(err, stdout) {
|
||||
|
||||
// Expands to directories by default
|
||||
var result = common.expand(['resources/*a*']);
|
||||
assert.equal(result.length, 4);
|
||||
assert.equal(result.length, 5);
|
||||
assert.ok(result.indexOf('resources/a.txt') > -1);
|
||||
assert.ok(result.indexOf('resources/badlink') > -1);
|
||||
assert.ok(result.indexOf('resources/cat') > -1);
|
||||
assert.ok(result.indexOf('resources/head') > -1);
|
||||
assert.ok(result.indexOf('resources/external') > -1);
|
||||
|
||||
// Check to make sure options get passed through (nodir is an example)
|
||||
|
||||
103
test/head.js
Normal file
103
test/head.js
Normal file
@ -0,0 +1,103 @@
|
||||
var shell = require('..');
|
||||
|
||||
var assert = require('assert');
|
||||
var fs = require('fs');
|
||||
|
||||
shell.config.silent = true;
|
||||
|
||||
shell.rm('-rf', 'tmp');
|
||||
shell.mkdir('tmp');
|
||||
|
||||
var result;
|
||||
|
||||
//
|
||||
// Invalids
|
||||
//
|
||||
|
||||
result = shell.head();
|
||||
assert.ok(shell.error());
|
||||
assert.equal(result.code, 1);
|
||||
|
||||
assert.equal(fs.existsSync('/asdfasdf'), false); // sanity check
|
||||
result = shell.head('/adsfasdf'); // file does not exist
|
||||
assert.ok(shell.error());
|
||||
assert.equal(result.code, 1);
|
||||
|
||||
//
|
||||
// Valids
|
||||
//
|
||||
|
||||
var topOfFile1 = ['file1 1', 'file1 2', 'file1 3', 'file1 4', 'file1 5',
|
||||
'file1 6', 'file1 7', 'file1 8', 'file1 9', 'file1 10',
|
||||
'file1 11', 'file1 12', 'file1 13', 'file1 14', 'file1 15',
|
||||
'file1 16', 'file1 17', 'file1 18', 'file1 19', 'file1 20'];
|
||||
var topOfFile2 = ['file2 1', 'file2 2', 'file2 3', 'file2 4', 'file2 5',
|
||||
'file2 6', 'file2 7', 'file2 8', 'file2 9', 'file2 10',
|
||||
'file2 11', 'file2 12', 'file2 13', 'file2 14', 'file2 15',
|
||||
'file2 16', 'file2 17', 'file2 18', 'file2 19', 'file2 20'];
|
||||
|
||||
// simple
|
||||
result = shell.head('resources/head/file1.txt');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, topOfFile1.slice(0, 10).join('\n')+'\n');
|
||||
|
||||
// multiple files
|
||||
result = shell.head('resources/head/file2.txt', 'resources/head/file1.txt');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, topOfFile2.slice(0, 10).concat(
|
||||
topOfFile1.slice(0, 10)
|
||||
).join('\n')+'\n');
|
||||
|
||||
// multiple files, array syntax
|
||||
result = shell.head(['resources/head/file2.txt', 'resources/head/file1.txt']);
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, topOfFile2.slice(0, 10).concat(
|
||||
topOfFile1.slice(0, 10)
|
||||
).join('\n')+'\n');
|
||||
|
||||
// reading more lines than are in the file (no trailing newline)
|
||||
result = shell.head('resources/file2', 'resources/file1');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, 'test2\ntest1'); // these files only have one line (no \n)
|
||||
|
||||
// reading more lines than are in the file (with trailing newline)
|
||||
result = shell.head('resources/head/shortfile2', 'resources/head/shortfile1');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, 'short2\nshort1\n'); // these files only have one line (with \n)
|
||||
|
||||
// Globbed file
|
||||
result = shell.head('resources/head/file?.txt');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, topOfFile1.slice(0, 10).concat(
|
||||
topOfFile2.slice(0, 10)
|
||||
).join('\n')+'\n');
|
||||
|
||||
// With `'-n' <num>` option
|
||||
result = shell.head('-n', 4, 'resources/head/file2.txt', 'resources/head/file1.txt');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, topOfFile2.slice(0, 4).concat(
|
||||
topOfFile1.slice(0, 4)
|
||||
).join('\n')+'\n');
|
||||
|
||||
// With `{'-n': <num>}` option
|
||||
result = shell.head({'-n': 4}, 'resources/head/file2.txt', 'resources/head/file1.txt');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, topOfFile2.slice(0, 4).concat(
|
||||
topOfFile1.slice(0, 4)
|
||||
).join('\n')+'\n');
|
||||
|
||||
// negative values (-num) are the same as (numLines - num)
|
||||
result = shell.head('-n', -46, 'resources/head/file1.txt');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, 'file1 1\nfile1 2\nfile1 3\nfile1 4\n');
|
||||
|
||||
shell.exit(123);
|
||||
50
test/resources/head/file1.txt
Normal file
50
test/resources/head/file1.txt
Normal file
@ -0,0 +1,50 @@
|
||||
file1 1
|
||||
file1 2
|
||||
file1 3
|
||||
file1 4
|
||||
file1 5
|
||||
file1 6
|
||||
file1 7
|
||||
file1 8
|
||||
file1 9
|
||||
file1 10
|
||||
file1 11
|
||||
file1 12
|
||||
file1 13
|
||||
file1 14
|
||||
file1 15
|
||||
file1 16
|
||||
file1 17
|
||||
file1 18
|
||||
file1 19
|
||||
file1 20
|
||||
file1 21
|
||||
file1 22
|
||||
file1 23
|
||||
file1 24
|
||||
file1 25
|
||||
file1 26
|
||||
file1 27
|
||||
file1 28
|
||||
file1 29
|
||||
file1 30
|
||||
file1 31
|
||||
file1 32
|
||||
file1 33
|
||||
file1 34
|
||||
file1 35
|
||||
file1 36
|
||||
file1 37
|
||||
file1 38
|
||||
file1 39
|
||||
file1 40
|
||||
file1 41
|
||||
file1 42
|
||||
file1 43
|
||||
file1 44
|
||||
file1 45
|
||||
file1 46
|
||||
file1 47
|
||||
file1 48
|
||||
file1 49
|
||||
file1 50
|
||||
50
test/resources/head/file2.txt
Normal file
50
test/resources/head/file2.txt
Normal file
@ -0,0 +1,50 @@
|
||||
file2 1
|
||||
file2 2
|
||||
file2 3
|
||||
file2 4
|
||||
file2 5
|
||||
file2 6
|
||||
file2 7
|
||||
file2 8
|
||||
file2 9
|
||||
file2 10
|
||||
file2 11
|
||||
file2 12
|
||||
file2 13
|
||||
file2 14
|
||||
file2 15
|
||||
file2 16
|
||||
file2 17
|
||||
file2 18
|
||||
file2 19
|
||||
file2 20
|
||||
file2 21
|
||||
file2 22
|
||||
file2 23
|
||||
file2 24
|
||||
file2 25
|
||||
file2 26
|
||||
file2 27
|
||||
file2 28
|
||||
file2 29
|
||||
file2 30
|
||||
file2 31
|
||||
file2 32
|
||||
file2 33
|
||||
file2 34
|
||||
file2 35
|
||||
file2 36
|
||||
file2 37
|
||||
file2 38
|
||||
file2 39
|
||||
file2 40
|
||||
file2 41
|
||||
file2 42
|
||||
file2 43
|
||||
file2 44
|
||||
file2 45
|
||||
file2 46
|
||||
file2 47
|
||||
file2 48
|
||||
file2 49
|
||||
file2 50
|
||||
1
test/resources/head/shortfile1
Normal file
1
test/resources/head/shortfile1
Normal file
@ -0,0 +1 @@
|
||||
short1
|
||||
1
test/resources/head/shortfile2
Normal file
1
test/resources/head/shortfile2
Normal file
@ -0,0 +1 @@
|
||||
short2
|
||||
12
test/resources/sort/file1
Normal file
12
test/resources/sort/file1
Normal file
@ -0,0 +1,12 @@
|
||||
22
|
||||
symbolic
|
||||
46 integers
|
||||
melt
|
||||
admiral
|
||||
aardvark
|
||||
scanner
|
||||
Dynamite
|
||||
Witness
|
||||
12345
|
||||
blackwater
|
||||
5 numbers
|
||||
12
test/resources/sort/file2
Normal file
12
test/resources/sort/file2
Normal file
@ -0,0 +1,12 @@
|
||||
admiral
|
||||
scanner
|
||||
5 numbers
|
||||
Witness
|
||||
46 integers
|
||||
12345
|
||||
Dynamite
|
||||
blackwater
|
||||
aardvark
|
||||
22
|
||||
symbolic
|
||||
melt
|
||||
12
test/resources/sort/sorted
Normal file
12
test/resources/sort/sorted
Normal file
@ -0,0 +1,12 @@
|
||||
12345
|
||||
22
|
||||
46 integers
|
||||
5 numbers
|
||||
aardvark
|
||||
admiral
|
||||
blackwater
|
||||
Dynamite
|
||||
melt
|
||||
scanner
|
||||
symbolic
|
||||
Witness
|
||||
12
test/resources/sort/sortedDashN
Normal file
12
test/resources/sort/sortedDashN
Normal file
@ -0,0 +1,12 @@
|
||||
aardvark
|
||||
admiral
|
||||
blackwater
|
||||
Dynamite
|
||||
melt
|
||||
scanner
|
||||
symbolic
|
||||
Witness
|
||||
5 numbers
|
||||
22
|
||||
46 integers
|
||||
12345
|
||||
94
test/sort.js
Normal file
94
test/sort.js
Normal file
@ -0,0 +1,94 @@
|
||||
var shell = require('..');
|
||||
|
||||
var assert = require('assert'),
|
||||
fs = require('fs');
|
||||
|
||||
shell.config.silent = true;
|
||||
|
||||
shell.rm('-rf', 'tmp');
|
||||
shell.mkdir('tmp');
|
||||
|
||||
var result;
|
||||
|
||||
var doubleSorted = shell.cat('resources/sort/sorted')
|
||||
.trimRight()
|
||||
.split('\n')
|
||||
.reduce(function(prev, cur) {
|
||||
return prev.concat([cur, cur]);
|
||||
}, [])
|
||||
.join('\n') + '\n';
|
||||
|
||||
//
|
||||
// Invalids
|
||||
//
|
||||
|
||||
result = shell.sort();
|
||||
assert.ok(shell.error());
|
||||
assert.ok(result.code);
|
||||
|
||||
assert.equal(fs.existsSync('/asdfasdf'), false); // sanity check
|
||||
result = shell.sort('/adsfasdf'); // file does not exist
|
||||
assert.ok(shell.error());
|
||||
assert.ok(result.code);
|
||||
|
||||
//
|
||||
// Valids
|
||||
//
|
||||
|
||||
// simple
|
||||
result = shell.sort('resources/sort/file1');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result + '', shell.cat('resources/sort/sorted'));
|
||||
|
||||
// simple
|
||||
result = shell.sort('resources/sort/file2');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result + '', shell.cat('resources/sort/sorted'));
|
||||
|
||||
// multiple files
|
||||
result = shell.sort('resources/sort/file2', 'resources/sort/file1');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result + '', doubleSorted);
|
||||
|
||||
// multiple files, array syntax
|
||||
result = shell.sort(['resources/sort/file2', 'resources/sort/file1']);
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result + '', doubleSorted);
|
||||
|
||||
// Globbed file
|
||||
result = shell.sort('resources/sort/file?');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result + '', doubleSorted);
|
||||
|
||||
// With '-n' option
|
||||
result = shell.sort('-n', 'resources/sort/file2');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result + '', shell.cat('resources/sort/sortedDashN'));
|
||||
|
||||
// With '-r' option
|
||||
result = shell.sort('-r', 'resources/sort/file2');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result + '', shell.cat('resources/sort/sorted')
|
||||
.trimRight()
|
||||
.split('\n')
|
||||
.reverse()
|
||||
.join('\n') + '\n');
|
||||
|
||||
// With '-rn' option
|
||||
result = shell.sort('-rn', 'resources/sort/file2');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result + '', shell.cat('resources/sort/sortedDashN')
|
||||
.trimRight()
|
||||
.split('\n')
|
||||
.reverse()
|
||||
.join('\n') + '\n');
|
||||
|
||||
shell.exit(123);
|
||||
105
test/tail.js
Normal file
105
test/tail.js
Normal file
@ -0,0 +1,105 @@
|
||||
var shell = require('..');
|
||||
|
||||
var assert = require('assert');
|
||||
var fs = require('fs');
|
||||
|
||||
shell.config.silent = true;
|
||||
|
||||
shell.rm('-rf', 'tmp');
|
||||
shell.mkdir('tmp');
|
||||
|
||||
var result;
|
||||
|
||||
//
|
||||
// Invalids
|
||||
//
|
||||
|
||||
result = shell.tail();
|
||||
assert.ok(shell.error());
|
||||
assert.equal(result.code, 1);
|
||||
|
||||
assert.equal(fs.existsSync('/asdfasdf'), false); // sanity check
|
||||
result = shell.tail('/adsfasdf'); // file does not exist
|
||||
assert.ok(shell.error());
|
||||
assert.equal(result.code, 1);
|
||||
|
||||
//
|
||||
// Valids
|
||||
//
|
||||
|
||||
var bottomOfFile1 = ['file1 50', 'file1 49', 'file1 48', 'file1 47', 'file1 46',
|
||||
'file1 45', 'file1 44', 'file1 43', 'file1 42', 'file1 41',
|
||||
'file1 40', 'file1 39', 'file1 38', 'file1 37', 'file1 36',
|
||||
'file1 35', 'file1 34', 'file1 33', 'file1 32', 'file1 31'];
|
||||
var bottomOfFile2 = ['file2 50', 'file2 49', 'file2 48', 'file2 47', 'file2 46',
|
||||
'file2 45', 'file2 44', 'file2 43', 'file2 42', 'file2 41',
|
||||
'file2 40', 'file2 39', 'file2 38', 'file2 37', 'file2 36',
|
||||
'file2 35', 'file2 34', 'file2 33', 'file2 32', 'file2 31'];
|
||||
|
||||
// simple
|
||||
result = shell.tail('resources/head/file1.txt');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, bottomOfFile1.slice(0, 10).reverse().join('\n')+'\n');
|
||||
|
||||
// multiple files
|
||||
result = shell.tail('resources/head/file2.txt', 'resources/head/file1.txt');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, bottomOfFile2.slice(0, 10).reverse().concat(
|
||||
bottomOfFile1.slice(0, 10).reverse()
|
||||
).join('\n')+'\n');
|
||||
|
||||
// multiple files, array syntax
|
||||
result = shell.tail(['resources/head/file2.txt', 'resources/head/file1.txt']);
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, bottomOfFile2.slice(0, 10).reverse().concat(
|
||||
bottomOfFile1.slice(0, 10).reverse()
|
||||
).join('\n')+'\n');
|
||||
|
||||
// reading more lines than are in the file (no trailing newline)
|
||||
result = shell.tail('resources/file2', 'resources/file1');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, 'test2\ntest1'); // these files only have one line (no \n)
|
||||
|
||||
// reading more lines than are in the file (with trailing newline)
|
||||
result = shell.tail('resources/head/shortfile2', 'resources/head/shortfile1');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, 'short2\nshort1\n'); // these files only have one line (with \n)
|
||||
|
||||
// Globbed file
|
||||
result = shell.tail('resources/head/file?.txt');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, bottomOfFile1.slice(0, 10).reverse().concat(
|
||||
bottomOfFile2.slice(0, 10).reverse()
|
||||
).join('\n')+'\n');
|
||||
|
||||
// With `'-n' <num>` option
|
||||
result = shell.tail('-n', 4, 'resources/head/file2.txt', 'resources/head/file1.txt');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, bottomOfFile2.slice(0, 4).reverse().concat(
|
||||
bottomOfFile1.slice(0, 4).reverse()
|
||||
).join('\n')+'\n');
|
||||
|
||||
// With `{'-n': <num>}` option
|
||||
result = shell.tail({'-n': 4}, 'resources/head/file2.txt', 'resources/head/file1.txt');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, bottomOfFile2.slice(0, 4).reverse().concat(
|
||||
bottomOfFile1.slice(0, 4).reverse()
|
||||
).join('\n')+'\n');
|
||||
|
||||
// negative values are the same as positive values
|
||||
result = shell.tail('-n', -4, 'resources/head/file2.txt', 'resources/head/file1.txt');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result, bottomOfFile2.slice(0, 4).reverse().concat(
|
||||
bottomOfFile1.slice(0, 4).reverse()
|
||||
).join('\n')+'\n');
|
||||
|
||||
shell.exit(123);
|
||||
Loading…
x
Reference in New Issue
Block a user