linux - Safer alternative to MATLAB's `system` command -
i have been using matlab's system
command result of linux commands, in following simple example:
[junk, result] = system('find ~/ -type f')
this works expected, unless user types matlab's command window @ same time. during long find
command not uncommon. if happens user's input seems mixed result of find
command (and things break).
as example, instead of:
/path/to/file/one /path/to/file/two /path/to/file/three /path/to/file/four
i might get:
j/path/to/file/one u/path/to/file/two n/path/to/file/three k/path/to/file/four
in order demonstrate easily, can run like:
[junk, result] = system('cat')
type command window , press ctrl+d close stream. result
variable whatever typed in command window.
is there safer way me call system commands matlab without risking corrupted input?
wow. behavior surprising. sounds worth reporting bug mathworks. tested on os x, , see same behavior.
as workaround, re-implement system()
using calls java.lang.process
, related objects in jvm embedded in matlab.
you'll need to:
- use polling keep matlab's own input, ctrl-c, live
- use shell processing instead of passing commands directly processbuilder support expansion of
~
, other variables , wildcards, , support specifying commands , arguments in single string matlab's system does. ** alternately, expose arguments-array form if want lower-level control , don't want deal escaping , quoting strings shell. both useful. - redirect output files, or periodically drain child process's output buffers in polling code.
here's example.
function [status,out,errout] = systemwithjava(cmd) %systemcmd version of system implemented java.lang features % % [status,out,errout] = systemwithcmd(cmd) % % written work around issue matlab ui entry getting mixed % output captured system(). if isunix % use 'sh -s' enable processing of single line command , expansion of ~ % , other special characters, matlab system() pb = java.lang.processbuilder({'bash', '-s'}); % redirect stdout avoid filling buffers mytempname = tempname; stdoutfile = [mytempname '.systemwithjava.out']; stderrfile = [mytempname '.systemwithjava.err']; pb.redirectoutput(java.io.file(stdoutfile)); pb.redirecterror(java.io.file(stderrfile)); p = pb.start(); raii.cleanupprocess = oncleanup(@() p.destroy()); raii.stdoutfile = oncleanup(@() delete(stdoutfile)); raii.stderrfile = oncleanup(@() delete(stderrfile)); childstdin = java.io.printstream(p.getoutputstream()); childstdin.println(cmd); childstdin.close(); else % todo: fill in windows implementation here end % poll instead of waitfor() ctrl-c stays live % try/catch mechanism lousy, there no isfinished() method. % done more cleanly java worker did waitfor() on % separate thread, , have gui event thread interrupt on ctrl-c. status = []; while true try status = p.exitvalue(); % if returned, means process finished break; catch err if isequal(err.identifier, 'matlab:java:genericexception') ... && isa(err.exceptionobject, 'java.lang.illegalthreadstateexception') % means child process still running % (seriously, java.lang.process, no "bool isfinished()"? % continue else rethrow(err); end end % pause allow ui event processing, including ctrl-c pause(.01); end % collect output out = slurpfile(stdoutfile); errout = slurpfile(stderrfile); end function out = slurpfile(file) fid = fopen(file, 'r'); raii.fid = oncleanup(@() fclose(fid)); out = fread(fid, 'char=>char')'; %' end
i tried out best could, , looks keeps child process's output separate keyboard input matlab ide. keyboard input buffered , executed additional commands after systemwithjava()
returns. ctrl-c stays live , interrupt function, letting child process killed.
Comments
Post a Comment