C++ ときどき ごはん、わりとてぃーぶれいく☆

USAGI.NETWORKのなかのひとのブログ。主にC++。

nodejs: child_process.spawn とシェル実行の方法の模範解答についてのメモ(あるいはバッドノウハウを広めないための自分用の戒めとしてのメモというかあけおめ生存報告のメモ)

最初に答え

let spawn = require('child_process').spawn;

// 模範解答(たぶん)
let p = spawn( 'echo', [ 'hoge' ], { 'shell': true } );

p.stdout.on( 'data', payload => console.log( `[spawn/stdout]: ${payload.toString().trim()}` ) )
p.stderr.on( 'data', payload => console.log( `[spawn/stderr]: ${payload.toString().trim()}` ) )
p.on( 'exit', exit_code => console.log( `[spawn/exit] ${exit_code}` ) )

参考

要点

  • spawn には第3仮引数の options というのがあります
  • optionsshell を定義すると、
    • true にすると実行環境に応じて、 Windows なら process.env.ComSpec から実質的には cmd 、 nodejs が UNIX として扱う環境では /bin/sh-c オプションを噛ませたシェル実行モードになります
    • false にするとシェルを介さずに spawn の第1仮引数の command を直接実行します
    • string 型の値を与えると、与えられた文字列をシェルコマンドと見做して、それに -c オプションを噛ませたシェル実行モードになります

例えば、 powershell をシェルとして実行したい場合は↓のようになります。

let spawn = require('child_process').spawn;

let p = spawn( 'Get-ChildItem', [ '..' ], { 'shell': 'powershell' } );
p.stdout.on( 'data', payload => console.log( `[spawn/stdout]: ${payload.toString().trim()}` ) )
p.stderr.on( 'data', payload => console.log( `[spawn/stderr]: ${payload.toString().trim()}` ) )
p.on( 'exit', exit_code => console.log( `[spawn/exit] ${exit_code}` ) )

powershell は通常は Windows 環境のシステム標準で PATH が通り、 PATHEXT に .EXE があり NTFScase-insensitive なので、実行ファイルのフルパスを書かなくても powershell だけで実行でき、かつ -c オプションが期待動作するのでこれで使えます。

おまけ

諸事情により7年ぶりに TypeScript でおもちゃを書きはじめました。それで、なんでわざわざこんなメモを残したのかというと、世の中にはしばしば公式ドキュメントを読めばきれいな実現方法が書いてあるのに、読まずに、"俺は試行錯誤の結果こうしたらできたからみんなもこうするといいよ"的な野良バッドノウハウがおそらく誰も悪意などなく意図せずとも広まりやすい言語というのがあります。それ自体は発生してしまったものですし、わざわざあちこちに公開されているバッドノウハウへたまたま見つけたからというだけで7年ぶりにちょっと触った程度の nodejs 初心者がマサカリを投げるほど、私は傲慢でも暇でも親切でもないのですが、自分用には面白い戒めにもなるな、と思い、少し丁寧にメモを残してみました。

// これは日本語に限らず、参考用にソースを眺めたOSSでも少なくなかったバッドノウハウの例です
let p = spawn( 'cmd', [ '/c', 'echo', 'this is a bad know-how; read the official document first.' ] )

私もたくさんのバッドノウハウを悪意はなくとも広めてしまっている事もあるのでしょうが、なかのひとの気持ちとしてはできるだけきれいに、かつ(複数の意味で)面倒なく快適に、これからもお鮨を食べ、フリッツを食べ、不幸よりも幸せを多く感じて2020年以降も生きたいと思います。

あけおめ。