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


9

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

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

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

[[-e: command not found

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


2
[[キーワードです -おそらくシェルの解析ツリーでは、キーワードを空白で
区切る

別の見方をすると、おそらく関数[[-を作成できます。シェルは、[do the function [[-on e]ではなく、[[を実行してe [フラグを解析します。
pbhj

回答:


15

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

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

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

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

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

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


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

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


3
kshの手動見積もりは実際にその場で行われていると思います。それは他のプログラミング言語に似ています:Cでは、charキーワードですが、それでも書き込むことはできませんcharsomeletter = 'A';し、見た後に停止するパーサを期待しますchar
ピーター-モニカを

質問の「char」の例と記号「[[」の例の主な違いは、英数字の識別子は、一般に、他と区別するためにスペース区切り文字が必要であることです。一方、トークンとしての特別な記号は、スペース区切り文字を必要としません。
AcBap

丁度。Cとの比較が役立つかどうかはわかりません。Cで言うi--<=++jと、コンパイラーはそれをとして解析しても問題ありませんi -- <= ++ j
スコット

@スコットCの比較は有用だと思います(Cの識別子では英数字としか使用できないので、これは二次的なことです_)。kshが持っている(として、オペレータ、および(echo hello)として解析します( echo hello )。それはしているif{[[、、その他のキーワード、およびifx{x、および[[xそれぞれ1トークンです-どのようにcharsomeletter1つのCトークンです。対照的に、引用符(xで囲まれていないkshは2つのトークンです-Cのi--2つのトークンはどうですか?演算子であることの概念的な意味はBourneスタイルのシェル(kshなど)とCの間で異なります。しかし、ピーターA.シュナイダーは、本当の語彙の類似性。
エリアカガン

2

注意すべき重要なこと[は、それがコマンドであり、[[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シェルとは何も理解できないため、独自のコマンドであると想定します。;-)


"%help [["は、 "[["が条件付きコマンドであることを示しています。パーサーが「[[」パターンを見つけてそれを条件付きコマンドの開始として扱うとすぐに停止できないのはなぜですか?
AcBap

@Myloti [[-eは、(奇妙に見える場合に)潜在的に有効なコマンド名です。
ゴードンデイヴィ

2

このスペースは排泄物であり、必須です。あなたが見ることができるように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おり、この質問ではそれらの動作は同じですがkshbash動作と内部構造にはいくつかの大きな違いがあるため、私は仮定に注意します。これは、shellcheckがbashスクリプトで機能するからといって、kshスクリプトには必ずしも適切なツールではない場合があります。さまざまな砲弾に接近する際に覚えておくべきこと
Sergiy Kolodyazhnyy

@SergiyKolodyazhnyy私は[[組み込みのルールを強調するためにshellcheckを使用して日和見的でした。私は決して推論にあったksh貝だったshellcheckのエラーを見つけることができる。私は他の人が感謝を期待kshし、bash二つの異なる通訳です。言及していただきありがとうございます。また、外部コマンド[[であるbashも組み込まれてい[ます。
WinEunuuchs2Unix

実際に[も:)の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 組み込み[効率のためである
Sergiy Kolodyazhnyy

2
Shellcheckは知っていkshます。ハッシュバングまたはを使用します-s ksh。ところで、kshとbashには[[「ビルトイン」がありますが、これは、組み込みシェルであるとは異なり、キーワードです。(ksh :; bash :)組み込みコマンドと外部コマンドは構文的に似ています。異なる点の1つは、引数の一部の展開を抑制することです。これは、組み込みとしてはできませんでした-組み込みではグループ化できなかったためです。これが(または)1つのトークンであることが奇妙に感じる理由かもしれません。ビルトインとキーワードは字句的には似ていますが、構文的には似ていないと言ってもいいと思います。@SergiyKolodyazhnyy[whence -v [ [[type [ [[[[[[[{{x[[x
エリアガケイガン

1
@EliahKagan実は、私はPOSIXはこの状況についてどう思うかについて正確な答えを得るためにU&Lに質問を掲載しました unix.stackexchange.com/questions/526574/... シェル言語がうまくいけば、誰かがより正式な用語でそれを説明することができ、複雑で十分です
Sergiy Kolodyazhnyy

1

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

BusyBoxは[[、たとえば外部コマンドとして提供しています。


0

[[-eシェル展開に参加できるので(のように使用できます

echo [[-e]*

間の文字で始まるすべてのファイルを表示するために、[e)包括的に、それがあれば、完全な混乱になる[]、通常の空白支配単語の分割に参加していない特殊文字でした。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.