** "Looks like JavaScript, brain (contents) is Ruby, (stability is AC / DC)" ** Scripting language Kinx ). The library is the life of the language. So how to use the library.
This time it's Process. I hurriedly decided that it was necessary to start a child process.
System.exec()
A command execution interface that has been provided as standard for a long time. It's easy because it simply calls system ()
at the C level, but it's inconvenient because it doesn't come back until it finishes, or it can't get standard output. However, since the command is executed via the shell, redirects can be used.
So, this time I made a Process
class that can do more things, so that is the favorite in this explanation.
Process
using Process
The Process library is not built-in as standard, so use the using directive to load it explicitly.
using Process;
Exec
Process object is created by new Process (command, opts)
. The argument is a command name and an array of arguments, or a command string. In the case of an array, it feels like passing arguments separately, and in the case of a command line character string, it is parsed internally and automatically decomposed into an array format.
[" ls "," -1 "]
." ls -1 "
.The created process object has the following methods.
Method | Overview |
---|---|
run() |
Start the process. |
launch() |
Start and disconnect the process. |
std() |
The option passed as an argument is returned.{ in: opts.in, out: opts.out, err: opts.err } |
Not running yet at this point. It starts when run ()
or launch ()
is performed. run ()
returns an object of the ProcessController
class.
Run
run ()
returns an object of the ProcessController
class.
var p = new Process(["cmd","arg1"]).run();
Launch
launch ()
returns nothing (or rather null). The method is to not take care of the child after pushing it out.
new Process(["cmd","arg1"]).launch();
ProcessController
The ProcessController
class returned byrun ()
has the following methods.
Method | Overview |
---|---|
isAlive() |
True if the process is alive, if it has already ended, ordetach False after being done |
wait() |
Waits for the process to end and returns the process exit code after the process ends.detach Then returns 0. |
detach() |
Detach the process |
detach ()
is detached after the process is started. On Linux, the behavior is slightly different from when it is separated by launch ()
, but what you want to do is the same. The internal operation is the same on Windows.
In Linux, the so-called ** double-fork ** method is used to disconnect at process startup, but this can only be used at process startup. It is virtually impossible to disconnect after starting a process, and the child will survive as a zombie unless it is properly wait
or waitpid
in the parent process.
So, at the moment of detach ()
, I start a thread just for waitpid
and take care of it until the child dies.
By the way, double-fork is Linux,
By using the function called ..., you can fork the process once it was forked, then terminate the first forked process in haste and let init manage the grandchild process.
The top parent process remembers the waitpid
of the first forked child. My grandchildren are the ones who take care of me.
Wait
The following is an example of waiting for the end and getting the end code.
var p = new Process(["cmd", "arg1"]).run();
var status = p.wait();
Of course, if you have detach
, you cannot get it (0 is returned).
Detach
The detach
that came out earlier. The process can also be detach
. If you separate it, the connection with the child will be cut off. You don't have to wait
and you don't have to worry about ending. Or rather, you can't do it even if you want to worry about it.
var p = new Process(["cmd", "arg1"]).run();
p.detach();
Pipe
I'm waiting for the pipe. The main purpose of creating Process
is a pipe. The most desired function is to freely connect the standard input / output to the child process to a pipe to exchange information.
The pipe is specified by ʻoptsof
new Process (cmd, opts)`. There are three types of parameters as follows.
Parameters | Contents |
---|---|
in |
Specify standard input. You can specify a pipe object, a string, $stdin |
out |
Specify standard output. You can specify a pipe object, a string, $stdout Or$stderr |
err |
Specify standard error output. You can specify a pipe object, a string, $stdout Or$stderr |
$ stdin
, $ stdout
, $ stderr
... Bind the input source and output destination to the standard input / output of this process.Create a pipe object with new Pipe ()
. Returns an array of two objects, [Read, Write]
, in pairs. The pipe object has the following methods.
Normally, the Write
pipe is specified as ʻout or ʻerr
of the child process to read from the Read
pipe.
Read Pipe
Close the pipe after run ()
. Because it is set when run ()
is done.
Method | |
---|---|
peek() |
Returns 0 if there is no data in the pipe, greater than 0 if there is.-1 is an error. |
read() |
Get all pipe data as a character string. If there is no data, an empty string is returned. |
close() |
Close the pipe. |
Write Pipe
Close the pipe after run ()
. Because it is set when run ()
is done.
Method | |
---|---|
write(data) |
Write data to the pipe. Not all can be written, and the number of bytes written is returned. |
close() |
Close the pipe. |
The general form is used as follows.
using Process;
var [r1, w1] = new Pipe();
var p1 = new Process([ "ls", "-1" ], { out: w1 }).run();
w1.close(); //I don't use it anymore so you can close it
while (p1.isAlive() || r1.peek() > 0) {
var buf = r1.read();
if (buf.length() < 0) {
System.println("Error...");
return -1;
} else if (buf.length() > 0) {
System.print(buf);
} else {
// System.println("no input...");
}
}
System.println("");
When using Write Pipe on the parent process side, it looks like this.
using Process;
//stdin reads from pipe and outputs to standard output
[r1, w1] = new Pipe();
var p1 = new Process("cat", { in: r1, out: $stdout }).run();
r1.close(); //I don't use it anymore so you can close it
//Send to stdin on p1
var nwrite = w1.write("Message\n");
w1.close(); //Pipe close, transmission end
p1.wait();
By the way, you can control standard output and standard error output.
new Process("cmd", { out: $stdout, err: $stdout }); //Merge standard error output with standard output
new Process("cmd", { out: $stderr, err: $stderr }); //Merge standard output with standard error output
new Process("cmd", { out: $stderr, err: $stdout }); //Swap
Pipeline
Connecting pipes is quite a tedious task (or rather, which one is ...?), So I also defined Process.pipeline
, which does it all at once. Finally, put a callback function and use it as follows.
var r = Process.pipeline(cmd1, cmd2, cmd3, ..., &(i, o, pipeline) => {
// i ...Write pipe to stdin for the first command
// o ...Read pipe from stdout of last command
// pipeline ...Pipeline object
// pipeline.input .......Same as i above
// pipeline.output ......Same as o above
// pipeline.peek() ...... pipeline.output.peek()Same as
// pipeline.read() ...... pipeline.output.read()Same as
// pipeline.write() ..... pipeline.input.write()Same as
// pipeline.isAlive() ...True if any process in the pipeline is alive
// pipeline.wait() ......Wait for all the processes in the pipeline to complete,
//Returns an exit code as an array
//Callback return value remains Process.pipeline()It becomes the return value of.
return pipeline.wait();
});
You can use it without calling back.
var pipeline = Process.pipeline(cmd1, cmd2, cmd3, ...);
// pipeline ...Pipeline object
//Omitted below.
The child process relationship is different between Windows and Linux, so it is a good point of the script to be able to handle such things in a unified manner. However, the commands themselves are different, so it's hard to absorb them. I'm a Windows user, but I use UnxUtils to make some Unix commands available at the command prompt. (I don't really like Cygwin because it changes the environment ...)
So, next time.