Loading
BLOG 開発者ブログ

2023年9月20日

シェルスクリプトをJSで実行できるNPMライブラリ”zx”を試してみました

はじめに

こんにちは、クラウドソリューショングループのshiba.mです。

皆さん、シェルスクリプト書いてますか。
頻繁に書く訳ではないものの、環境構築やコンソール操作などにおいて書かざるを得ない場面もありますよね。
そのたびにGoogle先生にシェルの書き方を教えてもらって記述して…となることも多いのではないでしょうか。

今回は、そんなシェルスクリプトをJavaScriptで記述し、実行できるようにするNPMライブラリ”zx”について紹介していきたいと思います。

目次

zxとは

https://github.com/google/zx
zxとは、GoogleのOrganization下で公開されている(※)NPMパッケージです。
※現在はAnton Medvedev氏個人によって保守されており、Googleの公式サポートは受けられない点はご注意ください。

2021年にはJavaScript Rising Starで一位になったのですが、それ以降あまり話題に挙がっていない印象です。

当時、自分も「面白いものが出たな…!」と注目していたのですが、その後の話をあまり聞かず、今回記事にしてみようと思ったのも「結構便利なパッケージなのに意外と知らない人が多い…?」と感じたからです。

利用できる場面は多々あると思いますので、本記事を参考に何か1つでも業務の効率化が図れれば幸いです。

インストールと実装

  1. インストールに必要なnodeのバージョン
    package.jsonを見る限り、zxにおいては16.0.0以上のnodeバージョンを要求しています。
    利用してみたい方は、ご自身のPCにインストールされているnodejsのバージョンについて確認してからインストールをお願いいたします。 
  2. インストール
    npm i -g zx

    でインストール可能です。
    インストールに成功した場合、zx -vを実行することでインストールされたzxのバージョン情報を確認できます。
    (バージョンは2023年9月19日現在のものになります)

    zx -v
    >> 7.2.3
  3. 実装と実行
    以下のファイルを実装し、testScript.mjsとして保存しておきます。
    .jsではなく.mjsとしているのは、zxの実行ファイルはtop-level-awaitによって記述する方が簡単だからです。
    .jsとして記述する場合は、一度functionで囲むなど、awaitが一番外に出るような記述を避ける必要があります。

    #!/usr/bin/env zx
    
    //配列は展開されるため、複数のオプションを指定したい場合には配列を利用すると簡潔に記述できます。
    const options = ['-al','--time-style=locale','--author']
    
    await $`ls ${options}`

    ファイルの権限に実行権限を追加しつつ、zxによって実行します。

    chmod +x testScript.mjs
    zx testScript.mjs

    実行すると、ls -al --time-style=locale --authorの実行結果が出力されます。

番外:npxによるインストール不要での実行

今回はnpmによってグローバルインストールを行った上でzxを実行しましたが、

npx zx testScript.mjs

のような形で頭にnpxをつけて実行するだけで、PCのローカル上にzxをインストールせずにzxを実行することも可能です。

zxの強み

  1. JavaScriptの記法によってシェルスクリプトを実行できる
    zxのセールスポイントであり、導入における最大の利点となります。
    zxを導入することで、学習すべき言語の対象を削ることができるようになります。
    (とはいえ、現状ではインタラクティブな実行ができないため、シンプルな処理をしたい場合はコマンド実行してしまう方が早いでしょうね。)
    JavaScriptの学習者数や、学習コストを考えると、将来的な保守・運用コストの削減も見込めると思います。 
  2. 非同期処理を分かりやすく記述・実行できる
    zxではJavaScriptの各関数が利用できるため、非同期処理に関してPromise.all()などを利用して対応することが可能です。

    #!/usr/bin/env zx
    
    await Promise.all([
     $`sleep 1; echo 1`,
     $`sleep 10; echo 10`
    ])

    シェルスクリプトにおいては、非同期による実行は扱いづらい面がありましたが、Promise.allが利用できることで簡潔に、わかりやすく記述することができます。
    環境構築などにおいて、競合しない複数のパッケージのインストールや、いくつかの実行ファイルのフェッチなどで利用すると便利そうです。

  3. markdownファイルに記載したコードブロックを実行可能
    zxでは、markdownファイルも実行対象となります。
    環境構築関連で利用する機会の多いシェルスクリプトに関して、説明文と実行文を同一のファイルに記載できるのは大きな強みではないでしょうか。
    例えば以下のようなmarkdownファイルを作成することで、コードブロック中に作成されたjsファイル(もしくはbashファイル)を実行します。

    テスト用のシェルスクリプト
    ## 説明
    これはテスト用のzx実行用ファイルとなります。
    markdownファイル内にコードブロックで記載したJavaScript、もしくはbashがzxの実行対象となります。
    ## コード
    ```js
    #!/usr/bin/env zx
    await $`echo 'this is test program hello world' | grep 'hello world'`
    ```
    ## 補足
    分割して記述した場合も実行されます。
    また、JavaScriptまたはbash以外で記述されたコードブロックについては無視されます。
    ## コードその2
    ```bash
    echo $(date)
    ```
  4. URLを指定することでリモートスクリプトの実行が可能
    以下のコマンドを実行することで、zxのGithub上に置かれているサンプルを実行することができます。

    zx https://raw.githubusercontent.com/google/zx/main/examples/interactive.mjs

    zx自体も、NPXによってインストール不要で実行することもできるので、nodejsさえインストールされていれば実行可能です。

さいごに

1か月に1回くらいは触る機会のあるシェルスクリプトを、効率的に記述できるようになるパッケージ”zx”の紹介でした。

利用場面は色々考えられます。Dockerの環境構築時に

RUN npx zx {リモートURL}

としてDockerFileの記述を簡潔にしたり、社内PCの初期セットアップ用の.shファイルを.mdファイルに更新して保守性とユーザビリティを高めたり…。細かい場面で、業務の効率化の手助けをしてくれるパッケージだと思います。

皆さんも是非一度使ってみてください。

shibamのブログ