Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
var ChildProcess = require('child_process');
var IS_WIN = process.platform === 'win32';
var TableParser = require('table-parser');
var parsePSOutput = require('./parse-output');

/**
* End of line.
* Basically, the EOL should be:
Expand Down Expand Up @@ -157,7 +159,7 @@ exports.lookup = function (query, callback) {
return callback(err);
}
else {
var processList = parseGrid(output);
var processList = IS_WIN ? parseGrid(output) : parsePSOutput(output);
var resultList = [];

processList.forEach(function (p) {
Expand Down
47 changes: 47 additions & 0 deletions lib/parse-output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
var split = require('split-string');
var EOL = /(\r\n)|(\n\r)|\n|\r/;

module.exports = parsePSOutput;

/**
* Parse the stdout into readable object.
* @param {String} output
*/
function parsePSOutput(output) {
var lines = (output || '')
.split(EOL)
.filter(function(p) {
return p !== undefined;
});

var header = lines[0] || '';
var fieldNames = splitLine(header);
var pidIdx = fieldNames.indexOf('PID');
var ppidIdx = fieldNames.indexOf('PPID');
var cmdIdx = fieldNames.indexOf('COMMAND');

return lines
.slice(1)
.map(function (line) {
var fields = splitLine(line);
var pid = fields[pidIdx];
var ppid = fields[ppidIdx];
var cmd = fields[cmdIdx];
var args = cmdIdx !== -1 ? fields.slice(cmdIdx + 1) : [];
return {
pid: pid,
command: cmd,
arguments: args,
ppid: ppid
};
})
.filter(function (proc) {
return proc.pid && proc.command;
});
}

function splitLine(line) {
return split(line, {sep: ' ', brackets: false, keepDoubleQuotes: true, keepSingleQuotes: true}).filter(function (word) {
return word !== '';
});
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"pid"
],
"dependencies": {
"split-string": "^3.0.2",
"table-parser": "^0.1.3"
},
"license": "MIT",
Expand Down
116 changes: 116 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var PS = require('../index');
var parsePSOutput = require('../lib/parse-output');
var CP = require('child_process');
var assert = require('assert');
var Path = require('path');
Expand Down Expand Up @@ -196,4 +197,119 @@ describe('test', function () {
});
});
});

describe('OSX formatted ps output', function () {
it('should be parsed correctly', function () {
var output =
'F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND\n' +
'4 1000 3002 1 20 0 45248 0 ep_pol Ss ? 0:00 /lib/systemd/systemd --user\n' +
'5 1000 3006 3002 20 0 163688 4 - S ? 0:00 (sd-pam)\n' +
'0 1000 3101 1 20 0 9657524 6355656 poll_s Sl ? 1440:57 mysqld --datadir /aa/aa/aa\n' +
'0 1000 3178 1 20 0 808752 247892 hrtime Sl ? 11234:03 ./aa -aa /aa/aa/aa/aa.aa -aa /aa/aa/aa/aa/aa/aa/aa -aa /aa/aa/aa/aa/aa/bb/bb.bb.bb.bb -t 4 -bb /cc/cc/cc/cc/cc/cc/cc.cc -cc /a/a/a/a/a/a/a.a\n' +
'0 1000 3198 1 20 0 639312 0 hrtime Sl ? 3:54 ./h -d /a/a/a -p 3\n' +
'0 1000 9215 1 20 0 1879292 95352 ep_pol Sl ? 47:06 node ./d/d\n' +
'0 1000 12547 1 20 0 1931424 21016 ep_pol Sl ? 0:14 node app.js --prod\n' +
'0 1000 17244 1 20 0 1450676 190724 ep_pol Sl ? 226:10 node app.js --prod --name="My app"\n' +
'1 1000 17789 1 20 0 79940 44376 - S ? 17:43 tor --runasdaemon 1\n' +
'5 1000 21352 21325 20 0 113860 1236 - S ? 0:01 sshd: user@pts/8\n' +
'0 1000 21353 21352 20 0 22676 3804 wait_w Ss+ pts/8 0:00 -bash\n' +
'5 1000 21675 21647 20 0 113868 1232 - S ? 0:00 sshd: user@pts/9\n' +
'0 1000 21676 21675 20 0 22788 4748 wait Ss pts/9 0:00 -bash\n' +
'0 1000 21973 21676 20 0 920496 28816 ep_pol Sl+ pts/9 0:00 node\n' +
'0 1000 21987 21973 20 0 28916 1500 - R+ pts/9 0:00 ps lx\n';
var parsedProcesses = parsePSOutput(output);
assert.deepEqual(parsedProcesses, [
{
'pid': '3002',
'command': '/lib/systemd/systemd',
'arguments': ['--user'],
'ppid': '1'
},
{
'pid': '3006',
'command': '(sd-pam)',
'arguments': [],
'ppid': '3002'
},
{
'pid': '3101',
'command': 'mysqld',
'arguments': ['--datadir', '/aa/aa/aa'],
'ppid': '1'
},
{
'pid': '3178',
'command': './aa',
'arguments': ['-aa', '/aa/aa/aa/aa.aa', '-aa', '/aa/aa/aa/aa/aa/aa/aa', '-aa', '/aa/aa/aa/aa/aa/bb/bb.bb.bb.bb', '-t', '4', '-bb', '/cc/cc/cc/cc/cc/cc/cc.cc', '-cc', '/a/a/a/a/a/a/a.a'],
'ppid': '1'
},
{
'pid': '3198',
'command': './h',
'arguments': [ '-d', '/a/a/a', '-p', '3'],
'ppid': '1'
},
{
'pid': '9215',
'command': 'node',
'arguments': ['./d/d'],
'ppid': '1'
},
{
'pid': '12547',
'command': 'node',
'arguments': ['app.js', '--prod'],
'ppid': '1'
},
{
'pid': '17244',
'command': 'node',
'arguments': ['app.js', '--prod', '--name="My app"'],
'ppid': '1'
},
{
'pid': '17789',
'command': 'tor',
'arguments': ['--runasdaemon', '1'],
'ppid': '1'
},
{
'pid': '21352',
'command': 'sshd:',
'arguments': ['user@pts/8'],
'ppid': '21325'
},
{
'pid': '21353',
'command': '-bash',
'arguments': [],
'ppid': '21352'
},
{
'pid': '21675',
'command': 'sshd:',
'arguments': ['user@pts/9'],
'ppid': '21647'
},
{
'pid': '21676',
'command': '-bash',
'arguments': [],
'ppid': '21675'
},
{
'pid': '21973',
'command': 'node',
'arguments': [],
'ppid': '21676'
},
{
'pid': '21987',
'command': 'ps',
'arguments': ['lx'],
'ppid': '21973'
}
]);
});
});
});