Bash条件式の一部の文字列比較演算子の周りにスペースを必要としないのはなぜですか?

Bash条件式の一部の文字列比較演算子の周りにスペースを必要としないのはなぜですか?

今日、私はbashスクリプトを書いて驚くべきことを見つけました。私はこれを最小限の例にまとめました。

[[ a>b ]]; echo $?

私の理解によると、周囲にスペースがないので、>文字列が空でないことをテストし、a>bエラーコードを返す必要があります0。ただし、上記のコマンドは1テストした両方のbashバージョンでエコーされます(詳細は以下を参照)。

また、以前の「good」コマンドを使用してtestテストしました。

[ a>b ]; echo $?echo 0(文字列がa空でないことをテストし、b現在の作業ディレクトリに空のファイルを作成します。>bこれは明らかにリダイレクトとして扱われ、理解できます)。

それからいくつかの他のことを試しました。

  • [[ b>a ]]; echo $?エコーが発生0し、ファイルは生成されません。
  • [[ b<a ]]; echo $?エコーが発生1し、ファイルは生成されません。
  • [[ a<b ]]; echo $?エコーが発生0し、ファイルは生成されません。
  • [ b>a ]; echo $?エコー0して空のファイルを作成しますa
  • [ b<a ]; echo $?不足しているファイルのエラーを報告し、そのaエラー1のためにエコーされます。
  • [ a<b ]; echo $?不足しているファイルのエラーを報告し、そのbエラー1のためにエコーされます。
  • [[ a=b ]]; echo $?期待どおりに0文字列が空でないことをテストするため、エコーされます。a=b
  • [ a=b ]; echo $?0同じ理由でエコ。
  • [[ a==b ]]; echo $?0同じ理由でエコ。
  • [ a==b ]; echo $?0同じ理由でエコ。
  • [[ a!=a ]]; echo $?どちらも[ a!=a ]; echo $?エコ0(予想)

<したがって、条件式では and の周囲の空白だけを省略できるように見えますが、文字列比較を行うことが目的の場合は省略できません。しかし、なぜこのように設計されたのでしょうか。これは私が見逃したものかもしれませんが、bashマニュアルのどこにも文書化されていないようです。>===!=

私の最初の問題は、条件式()のパターンの一部として>エスケープされていないものを使用しようとすることでした。[[ ... ]]私は最初にスペースで囲まない限り>問題なく使用できると思いました。条件付きでリダイレクトすることは意味がないからです(そして一部のテストが不可能であることが判明した後)、式は機能します。また。

しかし、これは真実ではないことが判明しました。もちろん簡単な解決策はエスケープ処理し>て作成する\>ことですが、なぜ必要なのか理解できません。

これはテストに使用したbashバージョンです。

GNU bash, version 5.2.2(1)-release (aarch64-unknown-linux-android)

そして

GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)

私の実験はenv -i bash --norc --noprofile

答え1

&これは、、、、、、、、タブなどの文字;です(|<>メタ文字シェル構文から。それらは独自のトークンを形成します(またはより多くのトークンに結合することができます(たとえば、、、;;... |&||。これは、文字²と数字が似ている、、、、[などの{文字とは異なります。!-=

Korn シェルの構成内では、[[...]]シェルは別個のマイクロ言語を理解していますが、外部とほぼ同じマークアップ規則に従います。

同じ理由で、外部では[[...]]次のことができます。

(echo a>file|tr a b&)

そしてそれを書く必要はありません:

( echo a > file | tr a b & )

それともそのようなものですif((1))then<file&&(uname)fi

ここでは、次のことができます。

[[(a>b||b<d)]]

(、および>はシェルメタ文字|です)

メタ文字を文字通り解釈するには、引用符('...'、、、、...を含む)で囲む必要があります"..."\$'...'

[[x]]シェルは1つの[[x]]トークンしか表示できないため、機能しません。そして、構成を[[開始するキーワード[[...]]も認識されません。マイクロ言語と[[ a==b ]]は異なり、単一のトークンなので、解釈はと同じです。[[ a == b ]][[...]]a==b[[ -n 'a==b' ]]

[それ自体は単なる一般的なコマンドなので、他のコマンドと同じ方法で解析されます。

[ a>b ]

[a引数で実行すると、]出力はwithまたは同様にリダイレクトされbます。[ a ] > becho a>b ]echo a ] > b>b echo a ]

内部的には((...))(kshとは異なり)Cに似た独自のマイクロ言語が提供されていますが、今回はトークン化規則が異なります。たとえば、((var=123+1))orを書くことができますが、orは必要((a==b))ありません。((var = 123 + 1))((a == b))


1は{中括弧拡張に参加し、シェル予約語でもありますが、トークン化後に処理されますが、割り当てを[解析するときにトークン化に参加します。引数として実行されずa[1 + 1]=foo、bashまたはksh(zshではない)から割り当てられた単語として解析されます。a[1はのような予約語ですが、履歴の拡張にも参加します。ただし、これはシェルの対話型呼び出しにのみ適用されます。+1]=foo!{

-²一部の演算子には文字が含まれていることに注意してください。[[...]]たとえば-nt、、、...-eq-lt

関連情報