必見!Electronのコマンド実行で注意すべき点

前回の記事、一気にWin,Mac,Linuxにアプリ開発!Electronを触ってみた感想(メリット6つ/デメリット3つ)でElectronのメリット/デメリットをまとめてみたわけですけど、さらに開発が進んだ結果として、一つ気をつけておかなかればいけない点が出てきました。

それは、ズバリ(Unix)コマンドを実行するときです。

例えば、「ls」コマンドを実行するとき、child_processspawn()なら、以下のように実行します。

const {spawn} = require('child_process');

let command = 'ls';
spawn('/bin/sh', ['-c', command]);

※コマンドをそのままテキストで実行できるよう、通常とは少し変形バージョンにしてます。

もちろん、「ls」は通常のコマンドなので問題はないんですけど、これが「Pythonコードを実行する」となると少し意味合いが変わってきます。

なぜなら、実行中にPythonを中断しようとしてもkillするための「pid」が見つからず、止められなくなってしまうのです。カッパえびせんのように。

元々、以下のようにspawn()の返り値にあるkill()を使えば処理を止めてくれるんですけど、これはシェル自身を止めるだけで、Pythonなど別プログラムまではめんどう見てくれない、ということのようです。(つまり2つプロセスが走る)

let childProcess = spawn('/bin/sh', ['-c', 'python test.py']);
childProcess.kill(); // ここでpythonは止まらない

じゃあ、spawn()の返り値の中から、pythonのpidを見つけて独自に中断すればいい・・・と思いきやpidはシェル自身のものしか見つからず、pythonのものは格納されていないようでした。

うーん、どうしたものか。

ひとつの解決法

色々と試しましたけど、結局は泥臭く「全てのプロセスの中から該当するものを検索して中断する」という方法しか見つかりませんでした。

コードとしては、以下のように「ps」と「grep」で中断したいプロセスを見つけ出し、process.kill()を使って処理を中断しました。

let command = 'ps -ef | grep "python" | grep "test.py" | awk \'{print $2}\'';
let childProcess = spawn('/bin/sh', ['-c', command]);
childProcess.stdout.on('data', (data) => {
    let pidStr = `${data}`;
    let pids = pidStr.split("\n");
    pids.forEach((pid) => {
        if(pid != '') {
            try {
                process.kill(pid);
            } catch(e) {}
        }
    });
});

いまのところは、これでうまくいってますけど、もっとスマートな解決法がありそうな気もしますね。ただ、stack overflowでも「コレ!」っていう決め手になるような解決法は見つからなかったですし、当分はこの方法で対処するしかなさそうです。

何かいいアイデアがあったら教えてください。m_ _m

ではでは〜!