Nick Bull Asked: 2020-02-05 11:47:38 +0800 CST2020-02-05 11:47:38 +0800 CST 2020-02-05 11:47:38 +0800 CST 外壳数学是否在子外壳中运行? 772 当我在 中执行简单的数学运算时#!/bin/sh,是否会创建一个子shell? 例如, addition=$(( 1 + 1 )) 语法会建议一个子shell,但我找不到任何东西 shell subshell 2 个回答 Voted Best Answer Stéphane Chazelas 2020-02-05T12:32:23+08:002020-02-05T12:32:23+08:00 $(cmd arg)在 subshell 环境中运行cmd,其输出(减去尾随换行符)成为扩展的结果。 (cmd arg)确实在子shell中运行,其输出不受影响。 所以$((cmd arg))将$(cmd arg)与额外的 subshell 层相同,但事实并非如此。 $((...))是来自 Korn shell 的一种单独的扩展形式。在 Korn shell 中,((arithmetic expression))计算算术表达式(遵循与 C 非常相似的语法),退出状态反映表达式解析为 0 还是非零。 这允许这样的事情: if ((var < 10)); then ... fi 这使它看起来非常相似C。 $用于引入扩展。就像$(cmd)is like(cmd)除了它扩展为 的输出cmd, $((arith))is like((arith))只是它扩展为算术表达式的评估结果。 POSIX,其sh主要基于 ksh88,指定$((...))但未指定((...)). 实际上,在较早的草案中,它是$[...]替代的,这就是为什么你发现它bash并zsh支持$[...]作为$((...)). IIRC,POSIX最初考虑将其指定为的主要原因$[...]是因为与命令替换中的子shell$((...))冲突。$((cmd arg)) 您会发现大多数 shell 正确识别$((echo x; echo y) | (tr xy ab))为不是算术扩展,但不是$((cmd arg)). 在任何情况下$((cmd))都意味着扩展到$cmd变量的算术值,而不是cmd. POSIX 规范中的相关文本有: shell命令语言的语法对于以“$((”开头的扩展有歧义,可以引入算术扩展或以子shell开头的命令替换。算术扩展优先;即shell首先确定是否它可以将扩展解析为算术扩展,并且仅在确定它不能将扩展解析为算术扩展时才将扩展解析为命令替换。shell 在执行此确定时不需要评估嵌套扩展。如果遇到结束在尚未确定不能将扩展解析为算术扩展的情况下,shell 应将扩展视为不完整的算术扩展并报告语法错误。符合要求的应用程序应确保在以子shell 开头的命令替换中将“$(”和“(”分隔为两个标记(即用空格分隔它们)。例如,包含单个子shell 的命令替换可以写成: ksh的((...))也与嵌套子壳冲突。虽然 POSIX 没有指定((...)),但它确实允许 ksh 的行为。 在实践中,当嵌套子外壳和/或 cmdsubsts 时,您应该确保在括号之间包含空格: echo "$( (...) )" ( (a; b) | (c;d) ) glenn jackman 2020-02-06T06:02:07+08:002020-02-06T06:02:07+08:00 这是一个不在子shell中运行的演示:您可以修改算术表达式中的变量: $ x=5; echo "$(( x *= 2 ))"; echo "$x" 10 10 如果它是一个子shell,echo $x将输出5. 使用 shell 算术时,请注意并非所有 shell 都支持前增量和后增量;(当前 Debian 和衍生版本中dash的默认值)将解释为变量而不是递增变量。/bin/sh$(( ++i ))$(( +(+i) ))i
$(cmd arg)
在 subshell 环境中运行cmd
,其输出(减去尾随换行符)成为扩展的结果。(cmd arg)
确实在子shell中运行,其输出不受影响。所以
$((cmd arg))
将$(cmd arg)
与额外的 subshell 层相同,但事实并非如此。$((...))
是来自 Korn shell 的一种单独的扩展形式。在 Korn shell 中,((arithmetic expression))
计算算术表达式(遵循与 C 非常相似的语法),退出状态反映表达式解析为 0 还是非零。这允许这样的事情:
这使它看起来非常相似
C
。$
用于引入扩展。就像$(cmd)
is like(cmd)
除了它扩展为 的输出cmd
,$((arith))
is like((arith))
只是它扩展为算术表达式的评估结果。POSIX,其
sh
主要基于 ksh88,指定$((...))
但未指定((...))
. 实际上,在较早的草案中,它是$[...]
替代的,这就是为什么你发现它bash
并zsh
支持$[...]
作为$((...))
.IIRC,POSIX最初考虑将其指定为的主要原因
$[...]
是因为与命令替换中的子shell$((...))
冲突。$((cmd arg))
您会发现大多数 shell 正确识别
$((echo x; echo y) | (tr xy ab))
为不是算术扩展,但不是$((cmd arg))
. 在任何情况下$((cmd))
都意味着扩展到$cmd
变量的算术值,而不是cmd
.POSIX 规范中的相关文本有:
ksh
的((...))
也与嵌套子壳冲突。虽然 POSIX 没有指定((...))
,但它确实允许 ksh 的行为。在实践中,当嵌套子外壳和/或 cmdsubsts 时,您应该确保在括号之间包含空格:
这是一个不在子shell中运行的演示:您可以修改算术表达式中的变量:
如果它是一个子shell,
echo $x
将输出5
.使用 shell 算术时,请注意并非所有 shell 都支持前增量和后增量;(当前 Debian 和衍生版本中
dash
的默认值)将解释为变量而不是递增变量。/bin/sh
$(( ++i ))
$(( +(+i) ))
i