理系学生日記

おまえはいつまで学生気分なのか

特定ディレクトリ配下にあるすべて package.json について yarn install を実行する。ただし node_modules 配下のものは除く

開発プロジェクトには便利ツールみたいなものを作って生産性アップの夢を見ることが多いです。 いまのプロジェクトでもその例外に漏れず、WIndows と Mac の二者がいるということもあって、node.js で CLI ツールを作っています。

そこで抱えている課題は、いろんなところにいろんなツールが置かれた結果として package.json が散在しているということ。 いろんなところで {yarn,npm} install することになってとにかく面倒だったので、

  1. package.json があるディレクトリに移動
  2. yarn install する

というのをサクっとやる方法が欲しかった。再帰的に package.json を見つけるのは find でできるんですが、上記のことを連続でやるのは厄介です。 なんでかっていうと、以下が理由。

  1. find -execxargs で 2 つのコマンドを同一シェル上で実行することができない (と理解している)
  2. node_modules 配下には山のように package.json があって、それは除外したい

というわけで、それをどう実行すれば良いかを考えました。

方法 1

$ find . -type d -name node_modules -prune -o -type f -name package.json -print0 | 
  xargs -0 -I{} sh -c 'cd $(dirname {}); yarn install'

まず find で node_modules 配下にはない package.json を探します。このパターンについては -name [それ以上下りたくないディレクトリ] -prune -o [実際に探したいファイルの条件] というのがぼくのイディオムです。良く引用するんですが、このあたりは以下を参照いただければ。

mollifier.hatenablog.com

package.json があるディレクトリを見つけたら、その後は xargs で実行します。 対象ディレクトリは dirname で取れるので、そこに cd したあとで yarn install すれば良い。

xargs で複数コマンドをどう実行したものかと思ったんですが、 sh を起動してやれば良かった。シンプルだった。

方法 2

こっちは試してないんですが、たぶん動く。何を使うかというと、 find には -execdir というオプションがあります。 これは、「対象ファイルがあるディレクトリをカレントディレクトリとして、exec を実行する」というもの。

    -execdir utility [argument ...] ;
             The -execdir primary is identical to the -exec primary with the exception that utility will be executed from the directory that holds the current file.  The filename sub-
             stituted for the string ``{}'' is not qualified.

これを使うと、上記はもっとシンプルに

$ find . -type d -name node_modules -prune -o -type f -name package.json -execdir yarn install \;

と書けるはず。