notebook

都内でWEB系エンジニアやってます。

zxでコマンドライン引数を扱う

zxに限らずだが、nodeでコマンドライン引数リストを参照するとき

コマンドライン引数をパースするライブラリを使っていない場合はprocess.argvからリストを取ってくる

zxでも単純にこれを使えばよいと思っていたが、zxのオプションを渡すとprocess.argvで渡ってくる順番が変わるのでそのまま使おうとすると当たり前だが挙動が変わってしまう

minimist

zxではminimistがデフォルトで含まれていて、最初からminimistでパースした引数のリストを参照できる(argv)

他のライブラリを使わない場合は、argvを最初から参照するのが良さそう

ただこれだけだとちょっと微妙で、次の2つのパターンのときにコマンドライン引数リストの内容が変わってしまう

  • オプションなし、キーと値がセットのオプションを渡したとき
    • eg) --shell=/bin/bash
  • (true/false)で表せるようなオプションを渡しているとき
    • eg) --quiet

argv._で取得できるコマンドライン引数のリストに自身のファイル名が含まれる場合と含まれない場合が出てくる

  • sample.mjs
#!/usr/bin/env zx

console.log(argv);
$ zx sample.mjs a b c
{ _: [ 'sample.mjs', 'a', 'b', 'c' ] }

$ zx --shell=/bin/bash sample.mjs a b c
{ _: [ 'sample.mjs', 'a', 'b', 'c' ], shell: '/bin/bash' }

$ zx --quiet sample.mjs a b c
{ _: [ 'a', 'b', 'c' ], quiet: 'sample.mjs' }

そこで、自身のファイル名がコマンドライン引数のリストに入っていても除外することで実行時のオプションによりコマンドライン引数リストの内容が変わってしまう現象を防ぐ

path

zxにはpathもデフォルトで含まれているので自身のファイル名をコマンドライン引数リストから除けば実行時のオプション内容によって影響を受けることはない

  • sample.mjs
#!/usr/bin/env zx

console.log(path.basename(__filename));
console.log(argv);
console.log(argv._.filter(a => a !== path.basename(__filename)));
$ zx sample.mjs a b
sample.mjs
{ _: [ 'sample.mjs', 'a', 'b' ] }
[ 'a', 'b' ]
$ zx --quite sample.mjs a b
sample.mjs
{ _: [ 'a', 'b' ], quite: 'sample.mjs' }
[ 'a', 'b' ]

これでオプションなどによって挙動に影響を与えるということはなくなったはず

余談

挙動の変更

ちょっと別の話だが、物によっては実行時にオプションを渡さず、コードの中でコントロールできるものもある

--quiteなどのオプションであれば

$.verbose = falseとコード中に書くことで制御可能

他にもREADMEに色々書いてある

google/zx: A tool for writing better scripts