Node.js は最近非常に人気があり、スクリプトをいくつか書いています。残念ながら、互換性は問題です。正式には、Node.jsインタープリターはnode
と呼ばれることになっていますが、DebianとUbuntuは代わりにnodejs
という実行可能ファイルを出荷しています。
Node.jsができるだけ多くの状況で動作するポータブルスクリプトが必要です。ファイル名がfoo.js
であると仮定すると、スクリプトを2つの方法で実行する必要があります。
./foo.js
は、node
またはnodejs
が$PATH
にある場合にスクリプトを実行します。node foo.js
もスクリプトを実行します(インタープリターがnode
と呼ばれると仮定)注:xavierm02と私自身の回答は、ポリグロットスクリプトの2つのバリエーションです。純粋なシバンソリューションが存在する場合、私はまだ関心があります。
私が思いついた最高のものは、実際にはポリグロット(Bourne Shell/Node.js)スクリプトであるこの「2行シバン」です。
_#!/bin/sh
':' //; exec "$(command -v nodejs || command -v node)" "$0" "$@"
console.log('Hello world!');
_
最初の行は、明らかに、Bourne Shell Shebangです。 Node.jsは、検出したShebangをすべてバイパスするため、Node.jsに関する限り、これは有効なJavaScriptファイルです。
2行目は、引数_:
_を使用してシェルの何もしない_//
_を呼び出し、このファイルの名前をパラメーターとしてnodejs
またはnode
を実行します。移植性のため、which
の代わりに_command -v
_が使用されます。コマンド置換構文$(...)
は厳密にはボーンではないため、1980年代にこれを実行する場合はバックティックを選択してください。
Node.jsは、文字列_':'
_を評価するだけです。これは何もしないようなもので、行の残りの部分はコメントとして解析されます。
ファイルの残りの部分は単純な古いJavaScriptです。サブシェルは、2行目のexec
が完了した後に終了するため、ファイルの残りの部分がシェルによって読み取られることはありません。
インスピレーションを与えてくれたxavierm02と、追加情報を提供してくれたすべてのコメント者に感謝します。
これは、ポリシーが理にかなっているDebianベースのシステムでのみ問題になります。
Fedoraがnodejsと呼ばれるバイナリをいつ提供したかはわかりませんが、見たことはありません。パッケージはnodejsと呼ばれ、nodeと呼ばれるバイナリをインストールします。
シンボリックリンクを使用して、Debianベースのシステムに常識を適用するだけで、適切なシバンを使用できます。他の人々はとにかく正気のシバンを使用しているので、あなたはそのシンボリックリンクを必要とするでしょう。
#!/usr/bin/env node
console.log("Spread the love.");
_#!/bin/sh
//bin/false || `which node || which nodejs` << `tail -n +2 $0`
console.log('ok');
_
_//bin/false
_は_/bin/false
_と同じですが、2番目のスラッシュがノードのコメントに変換する点が異なります。そのため、ここにあります。次に、最初の_||
_の右側が評価されます。引用符の代わりに逆引用符を付けた_'which node || which nodejs'
_はノードを起動し、_<<
_は右側のノードにフィードします。 Dancekのように_//
_で始まる区切り文字を使用することもできましたが、うまくいきましたが、最初に2行しかなくて済むので、_tail -n +2 $0
_を使用してファイル自体を読み取らせました最初の2行を除きます。
ノードで実行すると、最初の行はシバンとして認識されて無視され、2行目は1行のコメントになります。
(どうやら、sedはテールを置き換えるために使用できます 最初と最後の行なしでファイル内容を印刷する )
編集前の回答:
_#!/bin/sh
`which node || which nodejs` <<__HERE__
console.log('ok');
__HERE__
_
やりたいことを実行できないので、代わりにシェルスクリプトを実行して、_#!/bin/sh
_を実行します。そのシェルスクリプトは、ノードの実行に必要なファイルのパス、つまり_which node || which nodejs
_を取得します。バッククォートはここにあり、実行されるため、_'which node || which nodejs'
_(クォートの代わりにバッククォートを使用)は単にノードを呼び出します。次に、_<<
_を使用してスクリプトをフィードします。 ___HERE__
_は、スクリプトの区切り文字です。また、console.log('ok');
は、スクリプトに置き換える必要があるスクリプトの例です。
小さな.sh
ファイルを作成してもかまわない場合は、解決策をいくつかご紹介します。小さなシェルスクリプトを作成して、使用するノードの実行可能ファイルを決定し、Shebangでこのスクリプトを使用できます。
Shebang.sh:
#!/bin/sh
`which node || which nodejs` $@
script.js:
#!./Shebang.sh
console.log('hello');
両方を実行可能としてマークし、./script.js
を実行します。
このようにして、ポリグロットスクリプトを回避します。複数のシバン行を使用することは可能だとは思いませんが、良い考えのようです。
これはあなたが望む方法で問題を解決しますが、誰もこれを気にしていないようです。たとえば、 glifyjs および coffeescript は#!/usr/bin/env node
を使用し、 npm はシェルスクリプトをエントリポイントとして使用し、実行可能ファイルを明示的に再度呼び出します。名前はnode
です。私はUbuntuユーザーですが、常にノードをコンパイルしているため、これを知りませんでした。これをバグとして報告することを検討しています。
完全を期すために、2行目を実行する他の方法をいくつか示します。
// 2>/dev/null || echo yes
false //|| echo yes
しかし、どちらも選択した回答よりも優れています:
':' //; || echo yes
また、node
またはnodejs
(両方ではない)のいずれかが見つかることがわかっている場合は、次のように動作します。
exec `command -v node nodejs` "$0" "$@"
しかし、それは大きな「もし」であるので、私は選択された答えが最良の答えであり続けると思います。
これで問題が解決しないことは理解していますが、誤った前提で質問されたと確信しています。
Ubuntuはここで間違っています。独自のスクリプト用にユニバーサルシバンを作成しても、#!/usr/bin/env node
の事実上の標準を使用する、制御できない他のパッケージは変更されません。お使いのシステム必須 nodejsをターゲットとするスクリプトを実行したい場合は、node
にPATH
を提供します。
たとえば、Ubuntuが提供するnpm
パッケージでさえ、パッケージのシバンを書き換えません。
$ cd
$ rm -rf test_npm
$ mkdir test_npm
$ cd test_npm
$ npm install mkdirp 2>&1 | grep -ve home
`-- [email protected]
`-- [email protected]
npm WARN test_npm No description
npm WARN test_npm No repository field.
npm WARN test_npm No README data
npm WARN test_npm No license field.
$ node_modules/.bin/mkdirp testdir
/usr/bin/env: 'node': No such file or directory
$ head -n1 node_modules/.bin/mkdirp
#!/usr/bin/env node
$ npm --version
3.5.2
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.2 LTS"