我对 Bash 中“反向符号”功能的更好实现感兴趣。我知道我可以做类似的事情:
"$(($1 * -1))"
但这会产生一个没有符号的正数,但我需要带符号的返回值:
"$((-1 * -1))" == 1 # but I need '+1'
我当前的版本是:
# Reverts the +/- operators for an integer argument.
#
# $ polarize -1 # +1
# $ polarize +12 # -12
# $ polarize 2-2 # 2-2
# $ polarize - 1 # - 1
#
function polarize() {
[ $# -eq 0 ] && return
if [[ "$@" =~ ^-([[:digit:]]+)$ ]]; then
echo -n "+${BASH_REMATCH[1]}"
elif [[ "$@" =~ ^\+([[:digit:]]+)$ ]]; then
echo -n "-${BASH_REMATCH[1]}"
else
echo -n "$@"
fi
}
一些注意事项:
- 函数应仅处理有符号整数(即
-1
,+22
,但不处理0
或100
) - 如果没有参数,函数不应返回任何内容
- 函数应该正确处理多个参数(不执行任何操作)
答案1
使用printf
:
printf '%+d\n' "$(( -$n ))"
格式printf
字符串的%+d
意思是“将给定的参数打印为带有符号的十进制整数”。
所以你会得到类似的东西
revsign () {
if [ "$#" -eq 1 ] && [[ $1 =~ ^[+-][[:digit:]]+$ ]]; then
printf '%+d\n' "$(( -$1 ))"
fi
}
当给定多个参数或给定一个非有符号整数的参数时,这不会执行任何操作。
当有多个参数或单个参数不是带符号的整数时传递参数:
revsign () {
if [ "$#" -eq 1 ] && [[ $1 =~ ^[+-][[:digit:]]+$ ]]; then
printf '%+d\n' "$(( -$1 ))"
elif [ "$#" -gt 0 ]; then
printf '%s\n' "$@"
fi
}
如果您想小心并且不接受八进制数字(以 开头 编写0
,如 中034
)作为有效整数,请将正则表达式更改为
^[+-][1-9][[:digit:]]*$
答案2
既然你使用的是正则表达式,你不妨让它变得更好。
简单的^-([[:digit:]]+)$
只会捕获数字,而不捕获符号,并且:
要捕获任一标志,只需将正则表达式更改为:
^([+-])([0-9]+)$
请注意,符号 (
+
或-
) 是不是可选(?),它必须存在(根据您的要求)。不要像 008 那样删除前导零,这会引发错误:
008:无效的八进制数
改成:
^([+-])0*([0-9]+)$
从您的描述中不清楚是否可以允许空格和/或制表符,如果是的话,请更改为:
^[[:blank:]]*([+-])0*([0-9]+)$
然后,可以从以下内容重新构建正确的数字:
${BASH_REMATCH[1]}${BASH_REMATCH[2]}
或者,简单地说:
${BASH_REMATCH[@]:1:2}
整个脚本会变成这样:
#! /bin/bash
# Reverts the +/- operators for an integer argument.
#
# $ polarize -1 # +1
# $ polarize +12 # -12
# $ polarize 2-2 # 2-2
# $ polarize - 1 # - 1
#
polarize () {
re='^[[:blank:]]*([+-])0*([[:digit:]]+)$'
[[ $# -ne 1 ]] && return
[[ $1 =~ $re ]] || return
printf '<%+d>' "$(( -${BASH_REMATCH[@]:1:2} ))"
}
for n; do
printf '%s' "testing ==$n=="
polarize "$n"
echo
done
执行时(值列表对整个脚本有效,只是为了测试目的,该函数仅接受一个参数)(0、100 和其他一些测试没有输出):
$ ./testbash.sh +1 -1 +22 -12 0 100 2-2 "- 1" +008
testing ==+1==<-1>
testing ==-1==<+1>
testing ==+22==<-22>
testing ==-12==<+12>
testing ==0==
testing ==100==
testing ==2-2==
testing ==- 1==
testing ==+008==<-8>