「#!/ usr / bin / env bash」と「#!/ usr / bin / bash」の違いは何ですか?


372

Bashスクリプトのヘッダーで、これら2つのステートメントの違いは何ですか。

  1. #!/usr/bin/env bash

  2. #!/usr/bin/bash

私がenv マニュアルページを調べたとき、私はこの定義を得ました:

 env - run a program in a modified environment

どういう意味ですか?



6
なぜこの質問が閉じられているのか、「プログラミングまたはソフトウェア開発に関連する」がなぜ閉じられていないのか、誰に教えてもらえますか?
tarrsalah 2013年

1
私はそれが主題外ではないことに同意しますが、これはおそらくこのような他のいくつかの質問の複製です。
キース・トンプソン

16
この質問はトピック外としてマークされるべきではありませんでした。「オントピック」としてマークするには、スコアが3000を超える5人が必要であり、再開することができます。それは問題です-特にプログラミングについて。
Danijel-James W

3
びっくりしました。Linuxのドキュメントがトートロジーに満ちていることを知ってショックを受けました。xkcd.com/703 git-man-page-generator.lokaltog.net
allyourcode

回答:


323

介してコマンドを実行すると、/usr/bin/envプログラムのどのようなデフォルトのバージョンを探しているの利点は、あなたの現在であるたのenv ironment。

この方法では、システム上の特定の場所でパスを探す必要はありません。これらのパスは、システムによって場所が異なる場合があるためです。それがあなたのパスにある限り、それはそれを見つけます。

1つの欠点は、/usr/bin/env awk -fLinuxをサポートしたい場合は、複数の引数を渡すことができない(たとえば、を記述できない)ことです。これは、POSIXが行の解釈方法について曖昧であり、Linuxが最初の後にすべてを解釈するためです。単一の引数を表すスペース。の/usr/bin/env -S一部のバージョンでenvを使用してこれを回避できますが、スクリプトはさらに移植性が低くなり、かなり最近のシステム(たとえば、Ubuntu 16.04でも)で動作しなくなります。

もう1つの欠点は、明示的な実行可能ファイルを呼び出さないため、ミスの可能性があり、マルチユーザーシステムでセキュリティの問題(bashたとえば、パスで実行可能ファイルが呼び出された場合)です。

#!/usr/bin/env bash #lends you some flexibility on different systems
#!/usr/bin/bash     #gives you explicit control on a given system of what executable is called

状況によっては、最初の方が望ましい場合があります(複数のバージョンのpythonでpythonスクリプトを実行する場合など、実行可能行を作り直す必要はありません)。ただし、セキュリティが重視される状況では、コードインジェクションの可能性が制限されるため、後者が推奨されます。


22
もう1つの欠点は、インタープリターに追加の引数を渡すことができないことです。
キース・トンプソン

1
@KeithThompson:不正な情報.. / usr / bin / envを使用して、基礎となるインタープリターにオプションを渡すことができます!
Gaurav Agarwal 2014年

4
@GauravAgarwal:私のシステムにはありません。次の1行だけを含むスクリプト:#!/usr/bin/env echo Hello不平:/usr/bin/env: echo Hello: No such file or directory。どうやらそれはecho Helloへの単一の引数として扱われます/usr/bin/env
キーストンプソン

1
@AndréLaszlo:envコマンドは確かに引数をコマンドに渡すことができます。問題は行のセマンティクスであり#!、それはカーネルに依存します。最近のLinuxカーネルではのようなことができますが#!/usr/bin/env command args、古いLinuxカーネルや他のシステムではできません。
キーストンプソン

1
コードブロックにバッククォートがあるのはなぜですか?彼らは削除されるべきではないのですか?
ベンジャミンW.

64

を使用#!/usr/bin/env NAMEすると、シェルは$ PATH環境変数でNAMEの最初の一致を検索します。絶対パスを知らない場合や絶対パスを検索したくない場合に役立ちます。


9
少なくとも、envがどこにあるかを知る必要があります:)。
ᐅdevrimbaris

1
すばらしい答えです。「システム構成に基づいてプログラムを選択する」と言うのではなく、env shebangが何をするのかを簡潔に説明します
De Novo

13

のようにインタープリターへのパスを明示的に定義する代わりに/usr/bin/bash/、envコマンドを使用して、インタープリターが検索され、最初に見つかった場所から起動されます。これには良い面と悪い面の両方があります


ほとんどのシステムでは機能的には同じですが、bashおよびenv実行可能ファイルの場所によって異なります。ただし、これが環境変数にどのように影響するかはわかりません。
サファイ2013年

2
「インタープリターへのフルパスを指定することにより、envを使用せずにインタープリターを指定することが可能です。問題は、異なるコンピューターシステムでは正確なパスが異なる可能性があることです。envを使用する代わりに、インタープリターが検索され、次の場所に配置されます。スクリプトが実行される時間。これにより、スクリプトの移植性が向上しますが、実行可能な検索パス上のすべてのディレクトリで一致するものを検索するため、間違ったインタープリターが選択されるリスクも高まります。また、 envバイナリへのパスもマシンごとに異なる場合があります。 "
Mike Clark

10

シェルスクリプトがで始まる場合#!/bin/bash、それらは常にbashfromで実行され/binます。彼らはしかし、で起動した場合#!/usr/bin/env bash、彼らが探しますbash$PATH、その後、彼らは見つけることができる最初の1で始まります。

なぜこれが役立つのでしょうか?bashbash 4.x以降を必要とするスクリプトを実行したいが、システムにはbash3.x しかインストールされておらず、現在ディストリビューションで新しいバージョンが提供されていないか、管理者ではないため、システムにインストールされているものを変更できないとします。 。

もちろん、bashのソースコードをダウンロードして、独自のbashを最初から構築して~/bin、たとえば、それに配置することができます。そして、あなたはまた、あなたの修正することができ$PATH、あなたの中に変数を.bash_profile含めるファイル~/bin(最初のエントリとしてPATH=$HOME/bin:$PATHなど~で拡大しません$PATH)。ここでを呼び出すbashと、シェルは最初$PATHに順番に検索するため、で始まり~/bin、そこでが見つかりますbash。スクリプトがをbash使用して検索した場合も同じことが発生する#!/usr/bin/env bashため、これらのスクリプトはカスタムbashビルドを使用してシステムで動作します。

1つの欠点は、これが予期しない動作につながる可能性があることです。たとえば、同じマシン上の同じスクリプトが異なる環境の異なるインタープリターや異なる検索パスを持つユーザーで実行される可能性があり、あらゆる種類の頭痛の種となります。

最大の欠点envは、一部のシステムでは1つの引数しか許可されないため#!/usr/bin/env <interpreter> <arg>、システムが<interpreter> <arg>1つの引数として認識し(式が引用符で囲まれているかのように処理されるため)envという名前のインタープリターを検索するため、これを行うことができないことです<interpreter> <arg>。これはenvコマンド自体の問題ではないことに注意してください。常に複数のパラメーターを渡すことができましたが、を呼び出す前にこの行を解析するシステムのシバンパーサーを使用していますenv。その間、これはほとんどのシステムで修正されていますが、スクリプトを非常にポータブルにしたい場合は、実行するシステムで修正されているとは限りません。

たとえば、sudo環境$PATHをクリーンアップするように構成されていない場合や、クリーンアップから除外されている場合など、セキュリティに影響を与える可能性もあります。これを示しましょう:

通常/binは十分に保護された場所であり、rootそこにあるものを変更することしかできません。ただし、ホームディレクトリは、実行するどのプログラムでも変更できません。つまり、悪意のあるコードがbash隠しディレクトリに偽を配置.bash_profileし、そのディレクトリをに含めるようにを変更して$PATH、使用#!/usr/bin/env bashするすべてのスクリプトがその偽で実行されるようになる可能性があるということbashです。sudo続ければ$PATH、あなたは大きな問題を抱えています。

たとえば、ツールが~/.evil/bash次の内容のファイルを作成するとします。

#!/bin/bash

if [ $EUID -eq 0 ]; then
  echo "All your base are belong to us..."
  # We are root - do whatever you want to do
fi

/bin/bash "$@"

簡単なスクリプトを作ってみましょうsample.sh

#!/usr/bin/env bash

echo "Hello World"

概念実証(をsudo保持するシステム上$PATH):

$ ./sample.sh
Hello World

$ sudo ./sample.sh
Hello World

$ export PATH="$HOME/.evil:$PATH"

$ ./sample.sh
Hello World

$ sudo ./sample.sh
All your base are belong to us...
Hello World

通常、クラシックシェルはすべてに配置する必要/binがあり、何らかの理由でそこに配置したくない場合は/bin、実際の場所を指すシンボリックリンクを配置することは実際には問題で/binはありません(またはおそらくそれ自体がシンボリックリンクです)。私はいつもして行くだろう#!/bin/sh#!/bin/bash。これらが機能しなくなった場合に壊れる可能性が多すぎます。POSIXがこれらの位置を必要とするわけではありません(POSIXはパス名を標準化していないため、シバン機能もまったく標準化していません)。これらは非常に一般的であり、システムがを提供しない場合でも、/bin/shおそらく理解できます。#!/bin/shそしてそれで何をすべきかを知っており、それは既存のコードとの互換性のためだけのものかもしれません。

しかし、Perl、PHP、Python、Rubyなどの、より近代的で非標準のオプションのインタープリターの場合、実際に配置する場所は指定されていません。彼らは、であってもよい/usr/binが、彼らは同様であってもよく、/usr/local/binあるいは完全に異なる階層支店(中/opt/.../Applications/...など)。そのため、これらは#!/usr/bin/env xxxシバン構文をよく使用します。


4

envについて知らなかったときは、スクリプトを書き始める前に次のようにしていたので、便利だと思います。

type nodejs > scriptname.js #or any other environment

次に、ファイルのその行をシバンに変更していました。
私がこれを行っていたのは、自分のコンピュータのnodejsが/ usr / bin /または/ bin /のどこにあるかを常に覚えていなかったため、私にとってenv非常に便利です。これには詳細があるかもしれませんが、これが私の理由です

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.