1

我写以下代码:“((...))”与“(...)”有什么不同?

case "$2" in '+') ((res = $1 + $2));; 

       '-') ((res = $1 - $2));; 
esac 

echo $res 

用例:./"*filename*" 2 + 3

如果使用双括号,

((res = $1 + $2)) 

则结果被打印。但是,如果我使用单括号

(res = $1 + $2) 

然后没有打印。 ()(())之间的区别是什么?

+0

你是哪个外壳使用? – melpomene

+0

'((...))'用于[算术扩展](http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_04),而'(...)'运行封装在子shell中的命令,它不影响它的父shell。 – Jubobs

+0

此外,请注意,在您的示例中,第二个参数('$ 2')是操作符,而不是第二个操作数。因此,你可能需要'((res = $ 1 + $ 3))'和'((res = $ 1 - $ 3))',这里。 – Jubobs

回答

2

双括号((...))arithmetic expansion,而单括号(...)运行在一个subshell封闭命令,它有自己的范围,并且不影响它的父壳的环境。

这里,(res = $1 + $2),即使变量res成功分配到子shell的值,res留在母贝,这就解释了为什么没有获取打印取消设置。在这种情况下,您想使用((...))

此外,请注意,在您的示例中,第二个参数$2是运算符,而不是第二个操作数。因此,您需要使用((res = $1 + $3))((res = $1 - $3))

此外,对于稳健性,您可能希望确保

  • 参数的数目是有效的,
  • 第一和第三个参数是有效的整数,
  • 第二个参数是一个有效的算术运算器(+-,这里),

最后,为了改进跨不同壳体的可移植性,优选printf优于echo

修正和改进代码

#!/bin/sh 

# foo 

# Custom error function 
die() { 
    printf "%s\n" "$1" 1>&2 ; 
    exit 1; 
} 

# Function that returns an exit status of 
# 0 if its first argument is a valid integer, 
# 1 otherwise. 
is_integer() { 
    [ "$1" -eq 0 -o "$1" -ne 0 ] >/dev/null 2>&1 
} 

# Check that the number of argument is 3 
[ "$#" -eq 3 ] || die "invalid number of arguments" 

# Check that the operands are valid integers 
is_integer "$1" || die "invalid first operand" 
is_integer "$3" || die "invalid second operand" 

# If the second argument is a valid operator, assign res accordingly; 
# otherwise, die. 
case "$2" in 
    '+') 
    ((res = $1 + $3)) 
    ;; 
    '-') 
    ((res = $1 - $3)) 
    ;; 
    *) 
    die "invalid operator" 
    ;; 
esac 

printf "%s\n" "$res" 

测试

使得脚本后(所谓的 “富”)的可执行文件,运行

chmod u+x foo 

我得到下面的结果

$ ./foo -18 + 5 
-13 
$ ./foo 9 - 4 
5 
$ ./foo a + 2 
invalid first operand 
$ ./foo -18 + c 
invalid second operand 
$ ./foo 3/4 
invalid operator 
+2

掌声使用printf而不是echo。 – Jens