【问题标题】:Order of arithmetic expansion算术展开阶
【发布时间】:2012-04-22 00:05:30
【问题描述】:

考虑以下几点:

for i in 1 2 3; do echo $(( j += 1 ))& done

根据(我的阅读)sh language spec,第 2.3 节第 5 段,j += 1 的算术扩展应该在令牌识别期间发生,因此应该在 shell 读取 & 之前进行处理。因此,执行上述行似乎应该将j 增加 3,并且每次调用 echo 都应该得到一个不同的参数。 (如果 '&' 被 ';' 替换,这是什么行为)。在 bash 3.2.25 中,j 没有被修改。这是 bash 中的错误,还是我误解了什么?

【问题讨论】:

  • 对我来说,';' 似乎是合理的允许 j 的值在 $(( cmd )) 之间结转,而 '&' 在后台运行进程。值应该如何在后台进程之间“通信”,即如果您的简单案例 j += 1j=$(processThatRunsForHours) 替换怎么办?我不确定sh lang spec ';' 之间的区别在哪里并讨论了“&”。也许你会在那里得到一些见解。祝你好运。
  • 在 j=$( long_running_process ) 的情况下,我希望 shell 在完成之前一直阻塞,然后在后台生成 echo。
  • 您是否正在寻找可以追溯到 70 年代中期的代码库中的并发/并行性?我不认为这是一个错误,我认为这是向 bourne shell 后代 (ksh/bash) 添加功能同时“不破坏现有脚本”的逻辑结果。
  • @shelter 我不太明白你想说什么。 j + 1 的计算由 shell 在异步调用 echo 之前完成。
  • 证据告诉你什么?,在一种情况下是(';'),在另一种情况下('&')不是。只需阅读 posix 规范并在 Asynchronous Lists (2.9.3) 下找到它: shell 应在子 shell 中异步执行命令。这意味着 shell 在执行下一个命令之前不应等待命令完成。

标签: bash shell ksh zsh sh


【解决方案1】:

整个令牌识别部分处理解析,而不是扩展或任何类型的命令评估。看一下上下文的“介绍” - 解析基本上是所有事情之前,而算术表达式的评估通常是最后的评估步骤之一。在这里并不重要。

您实际上可能想知道扩展是否发生在子shell fork 异步列表之前。他们没有。

 $ ksh93 -c 'typeset -i n; while ((++j%10)); do { n+=1; printf "$n "; } & done; while ((++j%10)); do : $((n++)) ${ printf "$n " >&2;} & done 2>&1; echo'
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 $
 $ bash -c 'f() { printf "#%d %s, %s\n" "$@"; }; f 1 $BASHPID $$; f 2 $BASHPID $$ & sleep 1'      
#1 12275, 12275
#2 12276, 12275
 $

关于展开的顺序,算术展开与参数展开和命令替换同时进行,从左到右(也如上图第二个循环所示)。

我认为您不是唯一一个误读了该部分的人,我已经提交了许多与之相关的错误,这些错误要么是我的错误,要么是由于与非 POSIX 的一些不幸交互外壳扩展。恕我直言,该部分太简洁了。

如果您认为规范语言或实现存在问题,您可能会在其中一个邮件列表中找到更好的答案。 ast-usershelp-bashaustin group lists

【讨论】:

    猜你喜欢
    • 2013-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-16
    • 2010-10-13
    • 2020-02-03
    • 1970-01-01
    相关资源
    最近更新 更多