child_process.exec() 実行時にエイリアスを使えるようにする

Node.js 組み込みモジュール child_process が提供する exec() 関数は、シェルを起動して任意のコマンドが実行できる。パイプを駆使した簡単なシェルの結果をもって Node.js スクリプトを書いたりしたい時に向いている。

今回、この関数をゴリゴリに使うスクリプトを作ろうとしてつまづいたところがあるのでまとめておく。

目次

~/.bashrc を読み込まない

child_process#exec() でコマンドを実行すると、通常は /bin/sh で動作する。コレは shell オプションを指定することで Bash に変更できる。

しかし、Bash シェルを利用するようにしても、~/.bash_profile~/.bashrc が読み込まれない。つまり、これらのファイル内で定義したエイリアスを利用できないワケだ。

~/.bashrc を読み込ませるには

~/.bashrc などを読み込ませた状態で任意のコマンドを実行するには、次のように shopt コマンドと source コマンドを実行してから指定のコマンドを実行するようにしてやる。

const childProcess = require('child_process');
const util = require('util');

const execAsync = util.promisify(childProcess.exec);

// 実行したいコマンド
const inputCommand = `my_alias`;

(async () => {
  try {
    const result = await execAsync(`shopt -s expand_aliases ; \n source ~/.bash_profile ; \n ${inputCommand}`, {
      shell: '/bin/bash',
      cwd: '/PATH/TO/my-directory/'
    });
    console.log(result.stdout);
  }
  catch(error) {
    console.error(error.stderr ? error.stderr : error);
  }
})();

async・await で使えるように Promisify しているが、本質ではない。

shopt -s expand_aliases でエイリアスを使用するよう設定する。; \n でコマンドを区切り改行する。source ~/.bash_profile ないしは source ~/.bashrc など好きなファイルを読み込んでから、ようやく自分が実行したいコマンドを入力してやる。

exec() に指定するコマンド文字列の中で、セミコロンや改行を用いて複数のコマンドを実行する、という発想がなかったので驚いたが、こんなやり方で実現できた。