大括号扩展和参数扩展的顺序

时间:2020-08-27 10:37:42

标签: bash command-precedence

StackOverflow 上的常见错误是:x=99; echo {1..$x}为什么不起作用?” 答案是“因为括号在参数/变量之前被扩展了”

因此,我认为可以使用单个$和一个大括号来扩展多个变量。我希望a=1; b=2; c=3; echo ${{a..c}}打印1 2 3。首先,内部括号将扩展为${a} ${b} ${c}(在编写echo \${{a..c}}时会这样做)。然后该结果将进行参数扩展。
但是,我得到了-bash: ${{a..c}}: bad substitution,所以{a..c}根本没有扩展。

Bash's manual更加具体(强调我的意思)。

在将其拆分为令牌后,在命令行上执行扩展[...] 扩展顺序为:括号扩展;波浪号扩展,参数和变量扩展,算术扩展和命令替换(以从左到右的方式完成);分词;和文件名扩展。

请注意该列表中的;,。 “从左到右的方式”似乎适用于;之前的整个列表(因此是无序的)。就像数学运算符*/彼此之间没有优先级一样。

好吧,所以括号扩展的优先级确实比参数扩展高。只是{1..$x}${{a..c}}都是从左到右求值的,这意味着括号{在参数$x之前,参数${在参数{a..c}之前。大括号$

或者我想。但是,当使用${代替# in bash 5.0.3(1) x=nil; x1=one; x2=two echo ${x{1..2}} # prints `-bash: ${x{1..2}}: bad substitution` echo $x{1..2} # prints `one two` 时,左侧的参数会在右括号后的之后展开:

$x{1..2}

问题

  • 是bash手册有缺陷还是我读错了?
  • 如果手册存在缺陷:所有扩展的确切顺序是什么?

我只是问,因为我很好奇。我不打算在任何地方使用${array[@]:1:2}之类的思想。我对更好的解决方案替代方案对解决多个变量(例如数组切片Future < User > userLogin(email, password) async { try { Map body = { 'username': email, 'password': password }; http.Response response = await http.post(apiUrl, body: body); final responseBody = json.decode(response.body); final statusCode = response.statusCode; if (statusCode != HTTP_200_OK || responseBody == null) { throw new FetchDataException( "An error occured : [Status Code : $statusCode]"); } return new User.fromMap(responseBody); } catch (e){ print(e.toString()); } )不感兴趣。我只是想加深了解。

2 个答案:

答案 0 :(得分:2)

来自:https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html

为避免与参数扩展冲突,字符串“ $ {”不是 被认为适合大括号扩张,并禁止大括号扩张 直到结尾的“}”。

也就是说,对于echo $x{1..2},首先进行括号扩展,然后进行参数扩展,所以我们有了echo $x1 $x2。对于echo ${x{1..2}},大括号扩展不会发生,因为我们在${之后,还没有达到参数扩展的结尾}

关于您引用的bash手册部分,扩展仍然存在从左到右的顺序(相对于允许的嵌套部分)。如果您格式化列表而不是使用,;,事情就会变得更加清楚:

  1. 扩军
  2. 从左到右的方式:
    波浪号扩展,参数和变量扩展,算术扩展和命令替换
  3. 分词
  4. 文件名扩展。

答案 1 :(得分:0)

请阅读Mo Budlong于1988年编写的经典 Command Line Psychology ,该经典字体是为常规Unix编写的,但大多数仍然适用于bash。评估顺序为:

1 History substitution (except for the Bourne shell)
2 Splitting words, including special characters
3 Updating the history list (except for the Bourne shell)
4 Interpreting single and double quotes
5 Alias substitution (except for the Bourne shell)
6 Redirection of input and output (< > and |)
7 Variable substitution (variables starting with $)
8 Command substitution (commands inside back quotes)
9 File name expansion (file name wild cards) 

bash对类似{1..3}这样的代码的操作发生在上面的步骤7之前,这就是OP代码失败的原因。

但是,如果必须的话,总有eval(仅在事先知道变量或先仔细检查类型的情况下才应使用):

a=1; b=2; c=3; eval echo \{$a..$c}

输出:

1 2 3