共用サーバに置いていた/usr/local/nodejs/bin/npm
が消失するという奇怪な事件が発生した。この問題の原因はわからないが、とりあえず適当に復旧させようとおもって、npm周りを見ていた。npmというコマンドの実体はnpm-cli.jsへのシンボリックリンクになっている。
で、中身を見ていると次のようになっていた。
npm-cli.js
#!/bin/sh
// 2>/dev/null; exec "`dirname "$0"`/node" "$0" "$@"
;(function () { // wrapper in case we're in module_context mode
// windows: running "npm blah" in this folder will invoke WSH, not node.
if (typeof WScript !== "undefined") {
WScript.echo("npm does not work when run\n"
+"with the Windows Scripting Host\n\n"
+"'cd' to a different directory,\n"
+"or type 'npm.cmd <args>',\n"
+"or type 'node npm <args>'.")
WScript.quit(1)
return
}
process.title = "npm"
var log = require("npmlog")
log.pause() // will be unpaused when config is loaded.
log.info("it worked if it ends with", "ok")
...
ShellScriptとして実行できる
shebangを見るとどう見ても/bin/sh
である。それなのに、JavaScriptのコードが続いてるではないか。よくよく見ていると2行目が奇妙なことになっていることに気がつく。
npm-cli.js
#!/bin/sh
// 2>/dev/null; exec "`dirname "$0"`/node" "$0" "$@"
//
で始まってるので、JavaScriptではコメントとして処理される(shebangはどう扱われるんだろう?)。しかし、ShellScriptは//
でコメントアウトできないため、コマンドとして実行されてエラーになる。エラーになるけど、出力は/dev/nullに送られて、その後のコマンドが実行される。結果として、自分自身のファイル名がnodeコマンドの引数に渡されて実行される。
WSHとしても実行できる
続きをみると次のようになっている。
npm-cli.js
// windows: running "npm blah" in this folder will invoke WSH, not node.
if (typeof WScript !== "undefined") {
WScript.echo("npm does not work when run\n"
+"with the Windows Scripting Host\n\n"
+"'cd' to a different directory,\n"
+"or type 'npm.cmd <args>',\n"
+"or type 'node npm <args>'.")
WScript.quit(1)
return
}
WScriptというのはWindowsのWSHでしか定義されていないオブジェクトらしく、WSHとして実行されるとエラーメッセージを表示するようだ。
まとめ
いろんな環境に対応しててすごい。