九保すこひ@フリーランスエンジニア|累計300万PVのブログ運営中
前回の記事、一気にWin,Mac,Linuxにアプリ開発!Electronを触ってみた感想(メリット6つ/デメリット3つ)でElectronのメリット/デメリットをまとめてみたわけですけど、さらに開発が進んだ結果として、一つ気をつけておかなかればいけない点が出てきました。
それは、ズバリ(Unix)コマンドを実行するときです。
例えば、「ls」コマンドを実行するとき、child_processのspawn()なら、以下のように実行します。
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
ではでは〜!