我注意到它{
可以用于大括号扩展:
echo {1..8}
或在命令分组中:
{ls;echo hi}
bash 如何知道其中的区别?
答案1
一个简单的原因是存在一个字符:space。
大括号扩展不处理(未引用的)空格。
列表{...}
需要(不带引号的)空格。
更详细的答案是shell 如何解析命令行。
解析(理解)命令行的第一步是将其分为几个部分。
这些部分(通常称为单词或标记)是通过在每个元字符处划分命令行而产生的从链接:
- 将命令拆分为由固定元字符集分隔的标记: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 word
或argument
(在 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 点所述链接页面
- 检查每个命令的第一个标记是否为 .... 、 { 或 ( ,那么该命令实际上是一个复合命令。
你的例子:{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 ."