Bash 中反向符号的更好实现

Bash 中反向符号的更好实现

我对 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,但不处理0100
  • 如果没有参数,函数不应返回任何内容
  • 函数应该正确处理多个参数(不执行任何操作)

答案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>

相关内容