web-dev-qa-db-ja.com

kshの「[[」と「-e xxx」の間に空白が必要なのはなぜですか?

たとえば、次のコマンドは機能しません。

if [[-e xyz]]; then echo File exists;fi

kshは次のエラーを出します

[[-e: command not found

それは「[[-」があいまいだからですか?

9
Myloti

最も簡単な説明は、マニュアルでは[[ expression ]]と表記されているため、[[expressionの間にスペースがあり、]]を閉じる必要があるためです。しかし、もちろん、それをさらに詳しく調べることもできます。シェルはやや複雑な文法を持ち、「単語分割」の概念に大きく依存しています。特に、 ksh(1) 手動の状態:

シェルは、入力を単語に分解することで入力の解析を開始します。文字のシーケンスである単語は、引用符で囲まれていない空白文字(スペース、タブ、改行)またはメタ文字(<、>、|、;、&、(および))で区切られます。単語の区切り以外に、スペースとタブは無視されますが、改行は通常コマンドを区切ります。

したがって、マニュアルに記載されているように、文字列[[-eはシェルワードと見なされます。 kshは、組み込みコマンドと特殊演算子(forまたはwhileのような)のリストでそのようなコマンドを探し、次に外部コマンドを探します-そしてvoilà-見つかりません、したがって、コマンドが見つからないというエラーメッセージが表示されます。

この場合、[[も特別なメタ文字ではありません。もしそうなら、-e[[-e部分は、[[自体への引数ではなく、シェルワードと見なされます。ただし、[[は複合コマンドとして記述されており、マニュアルには次のように記載されています。

複合コマンドは、次の予約語を使用して作成されます-これらの単語は、引用符で囲まれておらず、コマンドの最初の単語として使用されている場合にのみ認識されます(つまり、パラメータの割り当てやリダイレクトの前に置くことはできません)。

したがって、[[が複合コマンドとして認識されるためには、コマンドまたはコマンドリストの最初のワードである必要があります。これは、「ワード」の以前の定義では、スペース、タブ、または改行で区切る必要があることを意味します。他の単語/引数。


あなたは コメント で質問しました:「なぜパーサーは "[["パターンを見つけてすぐに停止できず、それを条件付きコマンドの開始?」短い答えは、おそらく1)[構文の影響でした。これは、もともと外部コマンドであったためであり、POSIX標準準拠は今日でも外部コマンドとして存在します。2)シェルパーサーはそのように構築されているためです。シェルパーサーは、スペースで区切られていない他の特殊文字を認識できます。echo $((2+2))(echo foobar)は問題なく機能します。将来的には、kshの開発が再開したり、フォークやクローン(mkshpdkshなど)が出現したときに、誰かが[[-eにスペースのない構文を実装するようになるでしょう。

以下も参照してください。

15

スペースは デリミネーター であり、必須です。 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スクリプトで正確にその出力を提供します。

デリミネーターが必要な理由は トークンとレキシコン に関係しています。

2

注意する必要があるのは、[がコマンドであり、bashおよびkshのシェルキーワード[[[に基づいていることです。

[[は、[と同様の方法で使用されます。 時々動作を変更せずに[][[]]に置き換えることもできます。 [では、他のコマンドと同様に、コマンドとその引数の間にスペースが必要です。同じことが[[にも当てはまります。

以前は/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
  • [[[もコマンドではありません。完全なWord [[-eです。
  • if [[-eは、true/falseのテストを行います。 コマンド[[-eは存在しますか?

それは「[[-」があいまいだからなの?

はい。またはいいえ。 [[-eとは、シェルが理解できるものではないため、独自のコマンドであると想定しているためです。 ;-)

2
Rinzwind

[[は外部コマンドにすることができます!つまり、シェルで直接サポートされている構文ではなく、プログラムである可能性があります。スペースなしの構文をサポートすることはkshで可能ですが、外部[[を備えたシステムでは失敗するため、互換性の理由から、必要なスペースを維持することをお勧めします。

BusyBoxは外部コマンドとして[[を提供しています など。

1
DarkDust

[[-eはシェル拡張に参加できるため、次のように使用できます

echo [[-e]*

[eの間の文字で始まるすべてのファイルを一覧表示するには、[]が含まれていない特殊文字である場合、完全に混乱します。通常の空白で管理されるWord分割。

0
user968973