回答:
単純化された理由は、1つの文字の存在ですspace。
ブレース展開では、スペースは処理されません(引用符で囲まれていません)。
{...}
リストは、(非引用された)のスペースを必要とします。
より詳細な答えは、シェルがコマンドラインをどのように解析するかです。
コマンドラインを解析(理解)する最初の手順は、コマンドラインを部分に分割することです。
これらの部分(通常は単語またはトークンと呼ばれます)は、リンクの各メタ文字でコマンドラインを分割した結果です。
- コマンドを、メタ文字の固定セット(スペース、タブ、改行、;、(、)、<、>、|、および&)で区切られたトークンに分割します。トークンの種類には、単語、キーワード、I / Oリダイレクタ、セミコロンが含まれます。
メタ文字:spacetabenter;,<>|と&。
分割後、単語は(シェルで認識されるように)タイプになる場合があります。
LC=ALL ...
LC=ALL echo
LC=ALL echo "hello"
LC=ALL echo "hello" >&2
「スペース文字またはメタ文字を含まない」「中括弧」が単一の単語であり(上記のとおり)、引用符で囲まれていない場合のみ、「中括弧展開」の候補になります。後で内部構造に対してさらにチェックが実行されます。
したがって、これ{ls,-l}
は、「ブレース展開」として修飾されls -l
、first word
またはのいずれかになりますargument
(bashでは、zshは異なります)。
$ {ls,-l} ### executes `ls -l`
$ echo {ls,-l} ### prints `ls -l`
しかし、これはそうではありません{ls ,-l}
。Bashはspace、2つの単語として行を分割して解析します:{ls
そして、,-l}
どちらがトリガーされますcommand not found
(引数,-l}
は失われます):
$ {ls ,-l}
bash: {ls: command not found
あなたの行:2つのメタ文字との{ls;echo hi}
ため、「ブレース展開」になりません。;space
この3つの部分に分割され{ls
ますecho
hi}
。新しいコマンド:。ことを理解し;、新しいコマンドの開始をトリガします。コマンド{ls
は検出されず、次のコマンドが出力されますhi}
:
$ {ls;echo hi}
bash: {ls: command not found
hi}
他のコマンドの後に配置した場合、とにかく新しいコマンドを開始し;ます:
$ echo {ls;echo hi}
{ls
hi}
「複合コマンド」の1つは「ブレースリスト」(私の言葉)です{ list; }
。
ご覧のとおり、スペースと終了で定義されています;
。
スペースとは、;両方のために必要とされている{
と}
、「予約されている言葉」。
したがって、単語として認識されるには、メタ文字で囲まれている必要があります(ほとんどの場合:)space。
リンク先ページのポイント2で説明されているように
- 各コマンドの最初のトークンをチェックして、それが....、{、または(であるかどうかを確認します。その後、コマンドは実際には複合コマンドです。
あなたの例:{ls;echo hi}
リストではありません。
閉じて;、少なくとも1つのスペースが必要{です。最後}は、によって定義され;ます。
これはリスト{ ls;echo hi; }
です。これ{ ls;echo hi;}
も(あまり一般的ではありませんが、有効です)(@chorobaに感謝します)。
$ { ls;echo hi; }
A-list-of-files
hi
ただし、コマンドの引数(シェルは違いを知っている)として、エラーをトリガーします。
$ echo { ls;echo hi; }
bash: syntax error near unexpected token `}'
ただし、シェルが解析していると思われることに注意してください。
$ echo { ls;echo hi;
{ ls
hi
;
との間にスペースは必要ありません}
。{ ls;}
セミコロンはすでにメタ文字であるため機能します。
ブロック{
はシェルキーワードであるため、次の単語とスペースで区切る必要がありますが、中括弧の展開ではスペースはありません(スペースを中括弧で展開する必要がある場合は、エスケープする必要がありますecho {\ ,a}{b,c}
)。
コマンドの開始時にブレース展開を使用できます。
{ls,.} # expands to "ls ."
ただし、グループ化コマンドの解析は展開前に行われるため、ブロックに展開するために使用することはできません。
echo {'{ ls','.;}'} # { ls .;}
{'{ ls','.;}'} # bash: { ls: No such file or directory
コマンドラインの構文をチェックすることで認識します。同様に、式echo echo
では、最初のエコーをコマンドとして扱い、2番目のエコーを最初のエコーのパラメーターとして扱う必要があることを知っています。
bashでは、{ cmd; }
スペースとセミコロンが必要なので、非常に簡単です。ただし、たとえばzshでは必要ありませんが、それでも{}
シェルのコンテキストを分析することで、そのコンテンツで何をすべきかを知ることができます。
以下を考慮してください。
alias 1..3=date
{ 1..3; } #in bash
{1..3} #in zsh
どちらも現在の日付を返しますが、
echo {1..3}
戻り1 2 3
シェルは知っているので{}
、コマンドの引数にはecho
、その拡大すべきです。
{
引用符で囲まれていないスペースが続くと、bashでブレース展開が開始されません。
{
。シェルはコマンドライン全体をスペースで分割するため、引用符で囲まれていないスペースはどこにもできません。
まず、複合ブレースはそれ自体が単語であり、コマンドラインの最初の単語である必要があります。
echo { these braces are just words }
第二に、個々の中括弧は特別ではありません(上記を参照)。空の中括弧も特別ではありません:
echo {} # just the token {}: familiar from the find command
コンマのないものもそれ自体です
echo {abc} # just {abc}
ここからアクションが始まります。
echo {a,b} # braces disappear, a b results.
したがって、基本的にブレース展開を開始するには、単一の単語(空白でフィールドに分割されていない)が必要{...}
です。
これが可能な方法で、コマンドラインの最初の単語こと:
{ls,-l} . # just "ls -l ."
{
コマンドの先頭に表示される場合はコマンドリストとして解釈され、それ以外の場合はブレース展開として解釈される可能性があるようですが、よくわかりません。