Accessing Command-Line Functionality Within a Node Application
Problem
You want to access command-line functionality, such as ImageMagick, from within a
Node application.
Solution
Use Node’s child_process module. For example, if you want to use ImageMagick’s
identify, and then print out the data to the console, use the following:
var spawn = require('child_process').spawn, imcmp = spawn('identify',['-verbose', 'osprey.jpg']); imcmp.stdout.on('data', function (data) { console.log('stdout: ' + data); }); imcmp.stderr.on('data', function (data) { console.log('stderr: ' + data); }); imcmp.on('exit', function (code) { console.log('child process exited with code ' + code); });
EXPLAIN
The child_process module provides four methods to run command-line operations
and process returned data:
• spawn(command, [args], [options]): This launches a given process, with op‐
tional command-line arguments, and an options object specifying additional in‐
formation such as cwd to change directory and uid to find the user ID of the process.
• exec(command, [options], callback): This runs a command in a shell and buf‐
fers the result.
• execFile(file, [args],[options],[callback]): This is like exec() but exe‐
cutes the file directly.
• fork(modulePath, [args],[options]): This is a special case of spawn(), and
spawns Node processes, returning an object that has a communication channel built
in. It also requires a separate instance of V8 with each use, so use sparingly.
The child_process methods have three streams associated with them: stdin, stdout,
and stderr. The spawn() method is the most widely used of the child_process meth‐
ods, and the one used in the solution.
From the solution top, the command given is the
ImageMagick identify command-line application, which can return a wealth of in‐
formation about an image. In the args array, the code passes in the --verbose flag, and
the name of the image file.
When the data event happens with the child_pro
cess.stdout stream, the application prints it to the console. The data is a Buffer that
uses toString() implicitly when concatenated with another string. If an error happens,
it’s also printed out to the console.
A third event handler just communicates that the
child process is exiting.
If you want to process the result as an array, modify the input event handler:
imcmp.stdout.on('data', function (data) { console.log(data.toString().split("\n")); });
Now the data is processed into an array of strings, split on the new line within the identify output. If you want to pipe the result of one process to another, you can with multiple child processes.
If, in the solution, I want to pipe the result of the identify command to grep, in order to return only a subset of the information,
I can do this with two different spawn() commands In the code, the resulting data from the identify command is written to the stdin input stream for the grep command, and the grep’s data is then written out to the console.
Spawning two child processes to pipe the results of one command to another:
var spawn = require('child_process').spawn, imcmp = spawn('identify',['-verbose', 'fishies.jpg']), grep = spawn('grep', ['Resolution']); imcmp.stdout.on('data', function (data) { grep.stdin.write(data); }); imcmp.stderr.on('data', function (data) { console.log('stderr: ' + typeof data); }); grep.stdout.on('data', function (data) { console.log('grep data: ' + data); }); grep.stderr.on('data', function (data) { console.log('grep error: ' + data); }); imcmp.on('close', function (code) { console.log('child process close with code ' + code); grep.stdin.end(); }); grep.on('close', function(code) { console.log('grep closes with code ' + code); });
In addition, the application also captures the close event when the streams terminate (not necessarily when the child processes exit). In the close event handler for the identify child process, the stdin.end() method is called for grep to ensure it terminates.
The result of running the application on the test image is:
child process close with code 0 grep data: Resolution: 240x240 exif:ResolutionUnit: 2 exif:XResolution: 2400000/10000 exif:YResolution: 2400000/10000 grep closes with code 0
Note the order: the original identify child process stream terminates once its data is passed to the grep command, which then does its thing and prints out the target data (the photo resolution).
Then the grep command’s close event is processed. Instead of using a child process, if you have either GraphicsMagick or ImageMagick installed, you can use the gm Node module for accessing the imaging capability. Just install it as:
npm install gm
Of course, you can still use the child process, but using the GraphicsMagick module can be simpler.
Using Child Processes with Windows
The solution demonstrates how to use child processes in a Linux environment. There
are similarities and differences between using child processes in Linux/Unix, and using
them in Windows.
In Windows, you can’t explicitly give a command with a child process; you have to
invoke the Windows cmd.exe executable and have it perform the process. In addition,
the first flag to the command is /c, which tells cmd.exe to process the command and
then terminate.
Borrowing an example from Learning Node (O’Reilly), in the following code, the
cmd.exe command is used to get a directory listing, using the Windows dir command:
var cmd = require('child_process').spawn('cmd', ['/c', 'dir\n']); cmd.stdout.on('data', function (data) { console.log('stdout: ' + data); }); cmd.stderr.on('data', function (data) { console.log('stderr: ' + data); }); cmd.on('exit', function (code) { console.log('child process exited with code ' + code); });
No comments:
Post a Comment