web-dev-qa-db-ja.com

ノードファイルの先頭で「/ usr / bin / env node」は正確に何をしますか?

nodejsのいくつかの例の冒頭でこの行#!/usr/bin/env nodeを見て、その行の理由に答えられるトピックを見つけずにグーグルで検索しました。

単語の性質上、検索はそれほど簡単ではありません。

最近、いくつかのjavascriptnodejsの本を読んだことがありますが、それらのいずれかで見たことを覚えていませんでした。

例が必要な場合は、RabbitMQ official tutorial を見ることができます。ほとんどすべての例に含まれています。以下にその1つを示します。

#!/usr/bin/env node

var amqp = require('amqplib/callback_api');

amqp.connect('amqp://localhost', function(err, conn) {
  conn.createChannel(function(err, ch) {
    var ex = 'logs';
    var msg = process.argv.slice(2).join(' ') || 'Hello World!';

    ch.assertExchange(ex, 'fanout', {durable: false});
    ch.publish(ex, '', new Buffer(msg));
    console.log(" [x] Sent %s", msg);
  });

  setTimeout(function() { conn.close(); process.exit(0) }, 500);
});

誰かがこの行の意味を教えてくれますか?

この行を追加または削除した場合の違いは何ですか?どのような場合に必要ですか?

78
Gepser

インタプリタによって実行されるスクリプトには、通常、OSにそれらの実行方法を指示する シェバンライン があります。

最初の行が#!/bin/shであるfooという名前のスクリプトがある場合、システムはその最初の行を読み取り、/bin/sh fooに相当するものを実行します。このため、ほとんどのインタープリターは、スクリプトファイルの名前をコマンドライン引数として受け入れるように設定されています。

#!に続くインタープリター名はフルパスである必要があります。 OSは$PATHを検索してインタープリターを見つけません。

nodeによって実行されるスクリプトがある場合、最初の行を記述する明白な方法は次のとおりです。

#!/usr/bin/node

nodeコマンドが/usr/binにインストールされていない場合は機能しません。

一般的な回避策は、envコマンドを使用することです(この目的のために(reallyではありません)):

#!/usr/bin/env node

スクリプトの名前がfooの場合、OSは同等の処理を行います

/usr/bin/env node foo

envコマンドは、コマンドラインで指定された名前を持つ別のコマンドを実行し、そのコマンドに次の引数を渡します。ここで使用される理由は、env$PATHでコマンドを検索するためです。 node/usr/local/bin/nodeにインストールされていて、/usr/local/bin$PATHがある場合、envコマンドは/usr/local/bin/node fooを呼び出します。

envコマンドの主な目的は、変更された環境で別のコマンドを実行し、コマンドを実行する前に指定された環境変数を追加または削除することです。しかし、追加の引数なしで、変更されていない環境でコマンドを実行するだけです。この場合に必要なのはこれだけです。

このアプローチにはいくつかの欠点があります。最新のUnixライクシステムには/usr/bin/envがありますが、envコマンドが別のディレクトリにインストールされている古いシステムで作業しました。このメカニズムを使用して渡すことができる追加の引数には制限がある場合があります。ユーザーがいない場合、$PATHnodeコマンドを含むディレクトリがあるか、nodeの場合、間違ったコマンドを呼び出すか、まったく機能しない可能性があります。

他のアプローチは次のとおりです。

  • nodeコマンド自体へのフルパスを指定する#!行を使用し、異なるシステムの必要に応じてスクリプトを更新します。または
  • スクリプトを引数としてnodeコマンドを呼び出します。

#!/usr/bin/envトリックの詳細については、 この質問 (および 私の答え )も参照してください。

ちなみに、私のシステム(Linux Mint 17.2)では、/usr/bin/nodejsとしてインストールされています。私のメモによると、Ubuntu 12.04と12.10の間で/usr/bin/nodeから/usr/bin/nodejsに変更されました。 #!/usr/bin/envトリックはそれを助けません(シンボリックリンクなどをセットアップしない限り)。

更新:mtraceurによるコメントは(再フォーマットされた)と言います:

Nodejsとnodeの問題の回避策は、次の6行でファイルを開始することです。

#!/bin/sh -
':' /*-
test1=$(nodejs --version 2>&1) && exec nodejs "$0" "$@"
test2=$(node --version 2>&1) && exec node "$0" "$@"
exec printf '%s\n' "$test1" "$test2" 1>&2
*/

これは最初にnodejsを試行し、次にnodeを試行し、両方が見つからない場合にのみエラーメッセージを出力します。説明はこれらのコメントの範囲外であり、この回答が問題を引き起こしたため、問題に対処するのに役立つ場合に備えて、ここに残しておきます。

最近NodeJSを使用していません。私は、nodejsnodeの問題が、この回答を最初に投稿してから数年で解決されることを望んでいます。 Ubuntu 18.04では、nodejsパッケージは/usr/bin/nodejsへのシンボリックリンクとして/usr/bin/nodeをインストールします。いくつかの以前のOS(UbuntuまたはLinux Mint、どちらかわからない)では、nodenodejsへのシンボリックリンクとして提供するnodejs-legacyパッケージがありました。すべての詳細が正しいという保証はありません。

25
Keith Thompson

短い答え:通訳へのパスです。

編集(長い回答):「ノード」の前にスラッシュがない理由は、#!/ bin /の信頼性を常に保証できるとは限らないためです。 「/ env」ビットは、修正された環境でスクリプトを実行し、インタープリタープログラムをより確実に見つけることができるようにすることで、プログラムをよりクロスプラットフォームにします。

必ずしも必要ではありませんが、移植性(およびプロフェッショナリズム)を確保するために使用するとよいでしょう。

0
Quantum