支撑扩张

支撑扩张

我注意到它{可以用于大括号扩展:

echo {1..8}

或在命令分组中:

{ls;echo hi}

bash 如何知道其中的区别?

答案1

一个简单的原因是存在一个字符:space

大括号扩展不处理(未引用的)空格。

列表{...}需要(不带引号的)空格。

更详细的答案是shell 如何解析命令行


解析(理解)命令行的第一步是将其分为几个部分。
这些部分(通常称为单词或标记)是通过在每个元字符处划分命令行而产生的从链接:

  1. 将命令拆分为由固定元字符集分隔的标记:SPACE、TAB、NEWLINE、;、(、)、<、>、| 和 &。标记的类型包括单词、关键字、I/O 重定向器和分号。

元字符:spacetabenter;,<>|&

分割后,单词可能具有某种类型(如 shell 所理解的那样):

  • 命令预分配:LC=ALL ...
  • 命令LC=ALL echo
  • 论点LC=ALL echo "hello"
  • 重定向LC=ALL echo "hello" >&2

支撑扩张

仅当“大括号字符串”(没有空格或元字符)是单个单词(如上所述)并且是未引用,它是“括号扩展”的候选。稍后会对内部结构进行更多检查。

因此,这个:{ls,-l}符合“大括号扩展”的条件,可以成为ls -l, asfirst wordargument(在 bash 中,zsh 是不同的)。

$ {ls,-l}            ### executes `ls -l`
$ echo {ls,-l}       ### prints `ls -l`

但这不会:{ls ,-l}。 Bash 将拆分该space行并将其解析为两个单词:{ls并将,-l}触发 a command not found(参数,-l}丢失):

 $ {ls ,-l}
 bash: {ls: command not found

您的行:{ls;echo hi}不会成为“支撑扩展”,因为元字符;space.

它将分为三个部分:{ls新命令:echo hi}。了解触发;新命令的开始。该命令{ls将找不到,下一个命令将打印hi}

$ {ls;echo hi}
bash: {ls: command not found
hi}

如果它放在其他命令之后,它无论如何都会在之后启动一个新命令;

$ echo {ls;echo hi}
{ls
hi}

列表

“复合命令”之一是“大括号列表”(我的话):{ list; }
正如您所看到的,它是用空格和结束符定义的;。需要
空格 和 ,因为和都是“保留的”;{}”。

因此,要被识别为单词,必须被元字符包围(几乎总是:)space

如第 2 点所述链接页面

  1. 检查每个命令的第一个标记是否为 .... 、 { 或 ( ,那么该命令实际上是一个复合命令。

你的例子:{ls;echo hi}不是一个列表。

它需要一个结束符;和一个空格(至少){。最后一个}由结束语定义;

这是一个清单{ ls;echo hi; }。这{ ls;echo hi;}也是(不太常用,但有效)(感谢@choroba 的帮助)。

$ { ls;echo hi; }
A-list-of-files
hi

但作为命令的参数(shell 知道其中的区别),它会触发错误:

$ echo { ls;echo hi; }
bash: syntax error near unexpected token `}'

但要小心你认为 shell 正在解析的内容:

$ echo { ls;echo hi;
{ ls
hi

答案2

block{是一个shell关键字,所以它与下一个单词之间必须用空格分隔,而在大括号扩展中,不能有空格(如果需要大括号扩展空格,则必须对其进行转义:)echo {\ ,a}{b,c}

您可以在命令开头使用大括号扩展:

{ls,.}  # expands to "ls ."

但是,您不能使用它来扩展为块,因为分组命令的解析发生在扩展之前:

echo {'{ ls','.;}'}  # { ls .;}
{'{ ls','.;}'}       # bash: { ls: No such file or directory

答案3

它通过检查命令行的语法来知道。同样,它知道在表达式 中echo echo,第一个 echo 应该被视为命令,而第二个 echo 应该被视为第一个 echo 的参数。

在 bash 中它非常简单,因为{ cmd; }应该有空格和分号。然而,例如在 zsh 中它们是不需要的,但仍然通过分析{}shell 的上下文能够告诉应该如何处理其内容。

考虑以下:

alias 1..3=date
{ 1..3; }    #in bash
{1..3}       #in zsh

两者都返回当前日期,但是

echo {1..3}

返回,1 2 3因为 shell 知道{}command 的参数echo,所以应该扩展。

答案4

首先,复合大括号本身必须是一个单词,并且是命令行的第一个单词:

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 ."

相关内容