回答:
マニュアルにそれが表示されますので、最も簡単な説明は、なり[[ expression ]]
そうとの間にスペースが存在しなければならない[[
とexpression
して閉じます]]
。しかし、もちろん、それをさらに詳しく調べることもできます。シェルはやや複雑な文法を持ち、「単語分割」の概念に大きく依存しています。特に、 ksh(1)マニュアルには次のように記載されています。
シェルは、入力を単語に分解することで入力の解析を開始します。文字のシーケンスである単語は、引用符で囲まれていない空白文字(スペース、タブ、および改行)またはメタ文字(<、>、|、;、&、(および))で区切られます。単語の区切り以外に、スペースとタブは無視されますが、改行は通常コマンドを区切ります。
したがって、マニュアルに記載されているように、文字のシーケンスは[[-e
シェルワードと見なされます。ksh
組み込みおよび特殊演算子(for
またはのようなwhile
)のリストでそのようなコマンドを探し、次に外部コマンドを探します-そして、ボイラ-見つかりませんでした。そのため、コマンドが見つからないというエラーメッセージが表示されます。
この場合[[
も特別なメタ文字ではありません。もしそうなら、の-e
部分はそれ自身[[-e
への議論ではなく、シェルワードと考えられ[[
ます。ただし、[[
は複合コマンドとして説明されており、マニュアルには次のように記載されています。
複合コマンドは、次の予約語を使用して作成されます-これらの単語は、引用符で囲まれておらず、コマンドの最初の単語として使用されている場合にのみ認識されます(つまり、パラメータの割り当てやリダイレクトの前に置くことはできません)。
したがって[[
、複合コマンドとして認識されるためには、コマンドまたはコマンドリストの最初の単語である必要があります。これは、以前の「単語」の定義では、スペース、タブ、または改行で区切る必要があることを意味しています。単語/引数。
コメントで、「「[[」パターンが見つかり、それを条件付きコマンドの開始として扱うとすぐにパーサーが停止できないのはなぜですか?」短い答えは、おそらく1)[
もともと外部コマンドであったための構文の影響であり、POSIX標準準拠のために今日でも外部コマンドとして存在していること、および2)シェルパーサーがそのように構築されているためです。シェルパーサーは、スペースで区切られていない他の特殊文字を認識でき echo $((2+2))
、(echo foobar)
完全に正常に動作します。おそらくksh
開発が再開したり、フォークやクローン(mksh
またはpdksh
)があるように見えるときに、誰かがにスペースのない構文を実装するでしょう[[-e
。
[[
は、「予約語」と呼ばれます(シェルコマンド言語のセクション2.9を参照)。POSIXの定義では、予約語はスペースで区切る必要があります。対照的(
に、演算子であり、セクション2.9の標準状態で<blank>
は、「トークンの1つが演算子である場合、sが不要な一部の場所でのトークン間の間隔が表現に含まれています」。関連するディスカッションを参照してください: POSIXシェル文法:ブレースグループに最初のスペースが必要だがサブシェルには必要ないのはなぜですか?char
キーワードですが、それでも書き込むことはできませんcharsomeletter = 'A';
し、見た後に停止するパーサを期待しますchar
。
i--<=++j
と、コンパイラーはそれをとして解析しても問題ありませんi -- <= ++ j
。
_
)。kshが持っている(
として、オペレータ、および(echo hello)
として解析します( echo hello )
。それはしているif
、{
、[[
、、その他のキーワード、およびifx
、{x
、および[[x
それぞれ1トークンです-どのようにcharsomeletter
1つのCトークンです。対照的に、引用符(x
で囲まれていないkshは2つのトークンです-Cのi--
2つのトークンはどうですか?演算子であることの概念的な意味はBourneスタイルのシェル(kshなど)とCの間で異なります。しかし、ピーターA.シュナイダーは、本当の語彙の類似性。
注意すべき重要なこと[
は、それがコマンドであり、[[
bashとkshのshellキーワードがに基づいていること[
です。
[[
と同様に使用され[
ます。時にはあなたも置き換えることができる[
]
と[[
]]
行動に変化がありません。では[
、他のコマンドと同様に、コマンドとその引数の間にはスペースが必要です。同じことがにも当てはまります[[
。
以前はしかありませんでした/usr/bin/[
。現在、ほとんどのシェルは[
効率のために組み込まれていますが、構文は同じです。を提供するシェルでは[[
、のより汎用的な代替手段として機能し[
ます。
以下は、[
bash の説明です。
$ help [
[: [ arg... ]
Evaluate conditional expression.
This is a synonym for the "test" builtin, but the last argument must
be a literal `]', to match the opening `['.
つまり[
、test
(]
最後の引数を期待することを除いて)と同等です。help test
それについてさらに詳しく説明します。これをと比較できhelp [[
ます。
外部コマンド[
(man \[
)のmanページもあります。
の場合
if [[-e
[
も[[
コマンドもありません。完全な言葉[[-e
です。if [[-e
その真/偽のためのテストになります。それで、コマンドは[[-e
存在しますか? 「[[-」があいまいだからなのか?
はい。またはいいえ。[[-e
シェルとは何も理解できないため、独自のコマンドであると想定します。;-)
[[-e
は、(奇妙に見える場合に)潜在的に有効なコマンド名です。
このスペースは排泄物であり、必須です。あなたが見ることができるようにshellcheck
:
$ shellcheck gmail-browse-msgs-algorithm.sh
In gmail-browse-msgs-algorithm.sh line 847:
[[$Today != "${DaysArr[ i + DAY_DELETED_ON_NDX ]}" ]] && continue
^-- SC1035: You need a space after the [[ and before the ]].
(kshとbashの両方がサポートされて[[
おり、スペースがないと機能しません。Shellcheckは、そのバグのある行を含む同様のkshおよびbashスクリプトで正確にその出力を提供します。)
デリミネーターが必要な理由は、トークンとレキシコンに関係しています。
ksh
質問ではOPがシェルについて質問したことに注意してください。Bashは[[
演算子を借りてksh
おり、この質問ではそれらの動作は同じですがksh
、bash
動作と内部構造にはいくつかの大きな違いがあるため、私は仮定に注意します。これは、shellcheckがbashスクリプトで機能するからといって、kshスクリプトには必ずしも適切なツールではない場合があります。さまざまな砲弾に接近する際に覚えておくべきこと
[[
組み込みのルールを強調するためにshellcheckを使用して日和見的でした。私は決して推論にあったksh
貝だったshellcheck
のエラーを見つけることができる。私は他の人が感謝を期待ksh
し、bash
二つの異なる通訳です。言及していただきありがとうございます。また、外部コマンド[[
であるbashも組み込まれてい[
ます。
[
も:)のbashで、内蔵されてmanpages.ubuntu.com/manpages/bionic/man7/bash-builtins.7.htmlしかし、あなたは遠くじゃない- [
またはtest
外部コマンドであることが必要です。オリジナルのBourneシェルの日には[
、実際に外部コマンドで、まだのように、今日存在する/usr/bin/[
POSIXは、外部コマンドであることを、それを必要とするためpubs.opengroup.org/onlinepubs/009695399/utilities/test.html 非常に少数のは、POSIXにによって必要とされます内蔵さpubs.opengroup.org/onlinepubs/009695399/idx/sbi.html 組み込み[
効率のためである
ksh
ます。ハッシュバングまたはを使用します-s ksh
。ところで、kshとbashには[[
「ビルトイン」がありますが、これは、組み込みのシェルであるとは異なり、キーワードです。(ksh :; bash :)組み込みコマンドと外部コマンドは構文的に似ています。異なる点の1つは、引数の一部の展開を抑制することです。これは、組み込みとしてはできませんでした-組み込みではグループ化できなかったためです。これが(または)1つのトークンであることが奇妙に感じる理由かもしれません。ビルトインとキーワードは字句的には似ていますが、構文的には似ていないと言ってもいいと思います。@SergiyKolodyazhnyy[
whence -v [ [[
type [ [[
[[
[
[[
{
{x
[[x
[[-e
シェル展開に参加できるので(のように使用できます
echo [[-e]*
間の文字で始まるすべてのファイルを表示するために、[
とe
)包括的に、それがあれば、完全な混乱になる[
と]
、通常の空白支配単語の分割に参加していない特殊文字でした。
[[
はキーワードです -おそらくシェルの解析ツリーでは、キーワードを空白で