Bashスクリプトのヘッダーで、これら2つのステートメントの違いは何ですか。
#!/usr/bin/env bash#!/usr/bin/bash
私がenv マニュアルページを調べたとき、私はこの定義を得ました:
env - run a program in a modified environment
どういう意味ですか?
Bashスクリプトのヘッダーで、これら2つのステートメントの違いは何ですか。
#!/usr/bin/env bash
#!/usr/bin/bash
私がenv マニュアルページを調べたとき、私はこの定義を得ました:
env - run a program in a modified environment
どういう意味ですか?
回答:
介してコマンドを実行すると、/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スクリプトを実行する場合など、実行可能行を作り直す必要はありません)。ただし、セキュリティが重視される状況では、コードインジェクションの可能性が制限されるため、後者が推奨されます。
#!/usr/bin/env echo Hello不平:/usr/bin/env: echo Hello: No such file or directory。どうやらそれはecho Helloへの単一の引数として扱われます/usr/bin/env。
envコマンドは確かに引数をコマンドに渡すことができます。問題は行のセマンティクスであり#!、それはカーネルに依存します。最近のLinuxカーネルではのようなことができますが#!/usr/bin/env command args、古いLinuxカーネルや他のシステムではできません。
を使用#!/usr/bin/env NAMEすると、シェルは$ PATH環境変数でNAMEの最初の一致を検索します。絶対パスを知らない場合や絶対パスを検索したくない場合に役立ちます。
のようにインタープリターへのパスを明示的に定義する代わりに/usr/bin/bash/、envコマンドを使用して、インタープリターが検索され、最初に見つかった場所から起動されます。これには良い面と悪い面の両方があります
シェルスクリプトがで始まる場合#!/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シバン構文をよく使用します。