“((...))”与“(...)”有什么不同?
问题描述:
我写以下代码:“((...))”与“(...)”有什么不同?
case "$2" in '+') ((res = $1 + $2));;
'-') ((res = $1 - $2));;
esac
echo $res
用例:./"*filename*" 2 + 3
如果使用双括号,
((res = $1 + $2))
则结果被打印。但是,如果我使用单括号
(res = $1 + $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
你是哪个外壳使用? – melpomene
'((...))'用于[算术扩展](http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_04),而'(...)'运行封装在子shell中的命令,它不影响它的父shell。 – Jubobs
此外,请注意,在您的示例中,第二个参数('$ 2')是操作符,而不是第二个操作数。因此,你可能需要'((res = $ 1 + $ 3))'和'((res = $ 1 - $ 3))',这里。 – Jubobs