◆ package.json の bin で追加されたコマンドを実行できる
◆ npx はその場でダウンロードして実行もできる
◆ yarn は yarn2 の dlx コマンドでできるようになる

bin

npm パッケージはインストールするときに package.json の bin に設定されたコマンドが使えるようになります

npm にテスト用を置くのは気がすすまないので Gist にテスト用のパッケージを作りました

package.json はこうなっています

{
"name": "test-command",
"version": "1.0.0",
"bin": {
"test-comm1": "./cli.js",
"test-comm2": "./cli.js"
}
}

これをインストールします

yarn add gist:f403bc36fbdecc9199a3919a022e691f

インストール後の node_modules はこうなります

node_modules/
.bin/
test-comm1
test-comm1.cmd
test-comm2
test-comm2.cmd
test-command/
(略)

.bin

.bin フォルダに bin に設定したスクリプトが入っています
同じコマンドにファイルが 2 種類あるのは Windows と Linux 両方に対応するためのもので どっちでも指定したコマンドが実行できるようになっています

.bin フォルダにはパスは通っていないので

node_modules/.bin/test-command1 a b c

のように直接指定することになりますがこれは面倒です

yarn の場合は yarn run を使って .bin の中にあるコマンドを指定するとそれを実行してくれます

yarn run test-comm1 a b c

他の yarn コマンドとかぶらなければ run を省略しても動きます

yarn test-comm1 a b c

yarn じゃなくて npm の場合は npx というコマンドになります

npx test-comm1 a b c

実行例

実際に動かしてみます
cli.js は引数を表示するだけのものです

winuser@WIN10 MINGW64 /c/tmp/04
$ yarn run test-comm1
yarn run v1.22.4
warning package.json: No license field
$ C:\tmp\04\node_modules\.bin\test-comm1
cli arguments is ...
[
'C:\\Program Files\\nodejs\\node.exe',
'C:\\tmp\\04\\node_modules\\test-command\\cli.js'
]
Done in 0.18s.

winuser@WIN10 MINGW64 /c/tmp/04
$ yarn test-comm2
yarn run v1.22.4
warning package.json: No license field
$ C:\tmp\04\node_modules\.bin\test-comm2
cli arguments is ...
[
'C:\\Program Files\\nodejs\\node.exe',
'C:\\tmp\\04\\node_modules\\test-command\\cli.js'
]
Done in 0.17s.

npx

npx はインストールしたパッケージ以外にも使えます
node_modules に無いなら一時フォルダにダウンロードしてから実行されます

一応キャッシュが使われてるようなので 同じものを毎回ダウンロードしてるわけではなさそうです
ただ ローカルの PC 内で毎回展開したりの処理はあるのでインストール済みに比べると待ち時間はあります
頻繁に使うものなら package.json に追加してインストールしたほうがいいですが 一回限りでいいようなものでは便利です

winuser@WIN10 MINGW64 /c/tmp/07
$ npx gist:f403bc36fbdecc9199a3919a022e691f x y z
npx: 1個のパッケージを7.777秒でインストールしました。
cli arguments is ...
[
'C:\\Program Files\\nodejs\\node.exe',
'C:\\Users\\winuser\\AppData\\Roaming\\npm-cache\\_npx\\11624\\node_modules\\test-command\\cli.js',
'x',
'y',
'z'
]

npx を使うときは基本コマンドを選択できません
パッケージにコマンドが複数あって選択する場合は -p オプションを使ってパッケージを指定します

winuser@WIN10 MINGW64 /c/tmp/07
$ npx -p gist:f403bc36fbdecc9199a3919a022e691f test-comm2 x y z
npx: 1個のパッケージを8.33秒でインストールしました。
cli arguments is ...
[
'C:\\Program Files\\nodejs\\node.exe',
'C:\\Users\\winuser\\AppData\\Roaming\\npm-cache\\_npx\\5620\\node_modules\\test-command\\cli.js',
'x',
'y',
'z'
]

yarn dlx

npx のダウンロードして実行機能を yarn でも実行したかったのですが 存在しないようです
タイプミスとか フォルダ間違って実行した場合は普通はエラーになるだけなのに パッケージをダウンロードして実行することで予想外の動作があっても困りますからね
有名パッケージのありがちなタイプミスの名前で 「rm -rf /」 が実行されるパッケージとかあると怖いですし

とはいえ不便なので調べてみるとこんな issue がありました
https://github.com/yarnpkg/yarn/issues/3937

「yarn dlx」 という別の名前が提案されています
yarn2 のドキュメントを見ると dlx コマンドがありました

https://yarnpkg.com/cli/dlx

yarn2 からは使えるようです

実行したコマンドはわからない

上の方の結果を見ると分かる通り 引数の 0 番目が Node.js ランタイムの場所です
そして 1 番目が JavaScript ファイルで 2 番目以降がコマンドラインで渡した引数です
つまり bin コマンドのどっちを実行したかという情報がありません

Node.js みたいなランタイムを使わない実行可能ファイルだと 実体はひとつで別名のシンボリックリンクを用意して実行されたコマンド名に応じて処理を変えるというのはわりと見る方法です
それをやりたかったのですが Node.js では無理みたいですね

ただ npx の例でよく見る cowsay では cowthink を使ってるのを見た気がします
https://github.com/piuccio/cowsay

package.json は同じものを指定していて

  "bin": {
"cowsay": "./cli.js",
"cowthink": "./cli.js"
},

ヘルプメッセージにも cowthink で実行すると変わるようなことが書かれています

If the program is invoked as cowthink then the cow will think its message instead of saying it.

ソースコードを見ましたが コマンドライン引数を正規表現チェックして think で終わるかをチェックしていたので動くようには思えません
一応実行もしてみましたが常に say で think してくれませんでした

実行コマンド名での出し分けは無理そうなので package.json の bin で指定するファイルを変えたほうがよさそうです

[追記]

.bin フォルダ内がシンボリックリンクの場合には動くようです
シンボリックリンクの場合は cli.js へのシンボリックリンクとなります
この場合 最初の引数が Node.js ランタイムなのは変わりませんが その次の JavaScript ファイルがシンボリックリンクファイルの名前になります
これを見ることで実行したコマンドを判断することができます

ただ シンボリックリンクとして配置されるとは限らないので環境依存であることに注意が必要です