なぜ `[`はシェル組み込みコマンドで、 `[[`はシェルキーワードですか?


64

私の知る限り、[[はの拡張バージョンです[[[、キーワード[として表示され、組み込みとして表示されると混乱します。

[root@server ~]# type [
[ is a shell builtin
[root@server ~]# type [[
[[ is a shell keyword

TLDPは言う

ビルトインは同じ名前のシステムコマンドの同義語である場合がありますが、Bashは内部的に再実装します。たとえば、Bashのechoコマンドは/ bin / echoと同じではありませんが、動作はほとんど同じです。

そして

キーワードは、予約語、トークン、または演算子です。キーワードはシェルにとって特別な意味を持ち、実際、シェルの構文の構成要素です。例として、for、while、do、および!キーワードです。ビルトインと同様に、キーワードはBashにハードコーディングされますが、ビルトインとは異なり、キーワードはそれ自体がコマンドではなく、コマンド構成のサブユニットです。[2]

それは両方[[[キーワードを作るべきではありませんか?ここに欠けているものはありますか?また、このリンクの両方のことを再断言[とは[[同じ種類に属している必要があります。



9
/ bin / [は私のマシンに存在します。
ジョシュア

2
2つの違いの1つの簡単なデモンストレーションとして:if "[" $x -eq 3 ]期待どおりに動作します(Bashはと呼ばれるコマンドを探し[、これが存在するため)がif "[[" $x -eq 3 ]]動作しませ(再びBashは適切な名前のコマンドを検索しますが、[[コマンド)。
カイルストランド

1
@Joshuaそうでもありますが/usr/bin/echo、それは組み込みではないという意味ではありません。
ジョナサンラインハート

外部に存在するすべてのブリチンは、組み込みではない場合、引数を解析します。
ジョシュア

回答:


80

違い[とは[[、非常に基本的です。

  • [コマンドです。その引数は、他のコマンド引数が処理される方法と同じ方法で処理されます。たとえば、次のことを考慮してください。

    [ -z $name ]

    シェルは、他のコマンドの場合と同じように、結果に対して単語分割とファイル名生成の両方を展開$nameして実行します。

    例として、次は失敗します。

    $ name="here and there"
    $ [ -n $name ] && echo not empty
    bash: [: too many arguments
    

    これを正しく機能させるには、引用符が必要です。

    $ [ -n "$name" ] && echo not empty
    not empty
    
  • [[はシェルキーワードであり、その引数は特別な規則に従って処理されます。たとえば、次のことを考慮してください。

    [[ -z $name ]]

    シェルは展開します$nameが、他のコマンドとは異なり、結果に対して単語分割もファイル名生成も実行しません。たとえば、次のコードは、スペースが埋め込まれているにもかかわらず成功しますname

    $ name="here and there"
    $ [[ -n $name ]] && echo not empty
    not empty
    

概要

[ はコマンドであり、シェルが実行する他のすべてのコマンドと同じルールに従います。

[[ただし、コマンドではなくキーワードなので、シェルはそれを特別に扱い、非常に異なるルールで動作します。


+1。ありがとう。コマンドとキーワードが機能するルールのソース(リファレンス)を教えてください。
ティム

@Tim コマンドが動作するルールの詳細はにありman bashます。特に、「SIMPLE COMMAND EXPANSION」および「COMMAND EXECUTION」というタイトルのセクションを参照してください。加えて[[、他のbash のキーワードが含まれifthenwhile、および「ケース」。キーワードに関する一般的なルールはありません。各キーワードは特別なケースです。 man bash それぞれの詳細が含まれます。
John1024

62

V7 Unixの Bourneシェルはそのデビューをした- - [と呼ばれていたtest、そしてそれが唯一のように存在していました/bin/test。したがって、今日あなたが書くコードは:

if [ "$foo" = "bar" ] ; then ...

代わりに

if test "$foo" = "bar" ; then ...

この第二の表記法はまだ存在しますが、私はそれが何が起こっているのかについての詳細は明らかだということを見つける:あなたが呼ばれるコマンド呼び出しているtest引数を評価して返し、終了ステータスコードifの次の何をすべきかを決定するために使用します。そのコマンドはシェルに組み込まれている場合もあれば、外部プログラムの場合もあります。¹

[後の代替手段としてtest。²これはの組み込みの同義語かもしれませんが、組み込みシステムとしてそれを持たないシェル用の現代のシステムでtest提供さ/bin/[れています。

[そして、test同じコードを使用して実施することができます。これの場合である/bin/[/bin/testこれらはOS X、上のハードリンク結果と同じexecutable.³に、実装は完全に後ろを無視します]:あなたはとしてそれを呼び出す場合には、それを必要としない/bin/[、そしてそれは文句はありませんあなたがあればやるためにそれを提供/bin/test.⁴

[[と呼ばれる原始プログラムが決してなかったので、その歴史のどれも影響しません[[POSIXシェルの拡張として実装するシェル内にのみ存在します

「組み込み」と「キーワード」の違いの一部は、この歴史によるものです。また、解析のための構文規則という事実を反映[[して指摘したように式は、異なるJohn1024の答えを .⁵


脚注:

  1. そのように見る[と、他のほとんどのプログラミング言語で括弧やブラケットが機能する方法とは異なり、シェルスクリプトにスペースを入れる必要がある理由が明確になります。シェルのコマンドパーサーが許可した場合、許可if["$x"...する必要もあります。iftest"$x"...

  2. それは1980年頃に起こりました。1979年の/bin/[私の古代Unix V7のコピーには存在せずman test、別名として文書化されていません。私はのプレリリースコピーに持って対応するマニュアルページエントリでは、システムIIIの 1980年からのマニュアル、それがされて記載されています。

  3. ls -i /bin/[ /bin/test

  4. ただし、この動作に頼らないでください。Bashのビルトインバージョンに[は、終了が必要]であり、ビルトインtest実装は、提供すると文句を言います。

  5. 組み込みコマンドと外部コマンドの区別は、別の理由でも重要な場合があります。2つの実装の動作が異なる場合があります。これはecho多くのシステムに当てはまります。実装は1つしかないため、キーワードをそのように区別する必要はありません。


あなたは若い@Warren感謝が、なぜbuiltinkeyword区別の間[[[の両方が(事実を除いて同じ機能を提供する場合[[、より多くの機能よりも付属していますか[)?
スリー

2
@sreeを[[キーワードとすることで、bashは不可能なことを実行できます。[たとえば、シェルは変数であることを認識しているため、引用はそれほど必要ありません。つまり、コマンドラインの処理は、キーワードが使用されるときに影響を受けますが、組み込みが使用されるときは影響を受けません。
ムル

1
V7 Bourneシェル[のコードには組み込みが表示されていますが、コードはコメント化されています。
ステファンシャゼル

cdは組み込みですが、何も隠しません(cd外部プログラムとして実装することはできません)。
パエロエベルマン

2
これは優れた歴史的要約ですが、上記のmuruとその回答のJohn1024が指摘する(IMO)の重要な詳細は省略し[[ます。キーワードを作成すると、シェルは引数に特別な解析ルールを使用できます。したがって、残念ながら、私の賛成票はJohn1024になります。
イルマリカロネン

3

[当初は単なる外部コマンドであり、の別名です/bin/test。しかし、のようないくつかのコマンド、[およびはecho、シェルの実装は、シェル自体に直接コードをコピーではなく、別のプロセスに彼らが使用しているすべての時間を実行する必要がすることを決定したシェルスクリプトでそう頻繁に使用されています。これにより、これらのコマンドは「組み込み」になりましたが、外部プログラムはそのフルパスを介して呼び出すことができます。

[[ずっと後に来ました。ビルトインはシェル内で内部的に実装されますが、外部コマンドのように解析されます。John1024の答えで説明したように、これは引用符で囲まれていない変数は、単語の分割は、それらに行われ、トークンのように取得することを意味>し、<I / Oのリダイレクトとして処理されます。これにより、複雑な比較式の記述が不便になりました。[[これは、シェルシンタックスとして作成されたため、理想的に同期できます。内[[の変数の単語分割を得ることはありません、<>比較演算子として使用することができ、=これらが作るすべての便利されているなど、次のパラメータが引用されているか否かによって異なる動作をすることができ[[、従来のより使いやすい[コマンド/組み込み。

[何百万ものスクリプトに対する互換性のない変更であったため、このような構文として単純に再コーディングすることはできませんでした。[[以前は存在しなかった新しい構文を使用することにより、上位互換性のある方法で使用される方法を完全に改良することができました。

これは$((...))、算術式の構文をもたらした進化に似ており、従来のexprコマンドをほぼ置き換えました。


0

新しい[[ではbashある最適化[

古典的には、[それは毎回新しいプロセスを生成します:些細な操作を行うために頻繁に使われていたときに、一つの大きな欠点を持っている
(それはちょうど比較するための新しいアドレス空間を作成0して1!たびを!)

追加の主なポイントは、[[内部の式の評価が[余分なプロセスを引き起こさないようにすることだったと思います。しかし、[動作方法を変更することはできませんでした-それは多くの混乱と問題を作成します。そのため、最適化は新しい名前で、より効率的な方法、つまりシェル組み込みコマンドで実装されました。
副作用としてシェル構文のキーワードになりました。

最初[に使用された時点では、外部プロセスを使用する正しい方法でした


5
[もともとは外部コマンドでしたが、おそらくUnix System IIIがリリースされたときまでに、そして間違いなくUnix System Vがリリースされる前に、シェルにビルトインとして追加されたことに注意してください。したがって、「余分なプロセス」は長年の問題ではありませんでした。ただし、構文は変更されず、外部コマンドであるかのように扱われました。
ジョナサンレフラー

おかげで、ああ@JonathanLeffler、私は逃したことは[、両方です- ...いくつかの変更を意味する
フォルカー・シーゲル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.