Bash整数比较

55

我想编写一个Bash脚本,用于检查是否至少有一个参数,并且如果有一个参数,则检查该参数是否为0或1。

这是脚本:

#/bin/bash
if (("$#" < 1)) && ( (("$0" != 1)) ||  (("$0" -ne 0q)) ) ; then
    echo this script requires a 1 or 0 as first parameter.
fi
xinput set-prop 12 "Device Enabled" $0

这会导致以下错误:

./setTouchpadEnabled: line 2: ((: ./setTouchpadEnabled != 1: syntax error: operand expected (error token is "./setTouchpadEnabled != 1")
./setTouchpadEnabled: line 2: ((: ./setTouchpadEnabled -ne 0q: syntax error: operand expected (error token is "./setTouchpadEnabled -ne 0q")

我做错了什么?


看起来你正在使用 sh ./setTouchpadEnabled 运行你的脚本,而不是使用 bash。 - jordanm
@jordanm,你是在指缺少shebang行中的感叹号吗? - Kev
4个回答

56

这个脚本可用!

#/bin/bash
if [[ ( "$#" < 1 ) || ( !( "$1" == 1 ) && !( "$1" == 0 ) ) ]] ; then
    echo this script requires a 1 or 0 as first parameter.
else
    echo "first parameter is $1"
    xinput set-prop 12 "Device Enabled" $0
fi

但这个方法也可行,而且还保持了原始问题的逻辑,因为该问题是关于计算的。这里只使用算术表达式

#/bin/bash
if (( $# )) && (( $1 == 0 || $1 == 1 )); then
    echo "first parameter is $1"
    xinput set-prop 12 "Device Enabled" $0
else
    echo this script requires a 1 or 0 as first parameter.
fi

输出结果相同1:

$ ./tmp.sh 
this script requires a 1 or 0 as first parameter.

$ ./tmp.sh 0
first parameter is 0

$ ./tmp.sh 1
first parameter is 1

$ ./tmp.sh 2
this script requires a 1 or 0 as first parameter.

[1] 如果第一个参数是字符串,则第二个失败


非常感谢,错误是因为命令是xinput而不是input。 - Cheiron
你为什么没有使用问题中也用到的算术表达式,比如(())?有什么特别的原因吗? - 0xC0000022L
1
@user828193:显然这是关于计算的,所以算术表达式是最好的选择。这就是为什么我觉得你在回答中改变了问题的这个方面很让人恼火。 - 0xC0000022L
@ 0xC0000022L:你是对的!这里使用算术表达式。我想我被 OP 代码中的“-ne”和与可能为空的字符串的比较所带走了... - user000001

19

更简单的解决方案;

#/bin/bash
if (( ${1:-2} >= 2 )); then
    echo "First parameter must be 0 or 1"
fi
# rest of script...

输出

$ ./test 
First parameter must be 0 or 1
$ ./test 0
$ ./test 1
$ ./test 4
First parameter must be 0 or 1
$ ./test 2
First parameter must be 0 or 1

说明

  • (( )) - 使用整数计算表达式。
  • ${1:-2} - 使用参数扩展,如果未定义,则设置值为2
  • >= 2 - 如果整数大于或等于2,则为真。

+1,这暴露并解决了“((”命令的一个不太好的行为,即将值0分配给空或未设置的变量。 - SpinUp __ A Davis

9

在shell命令中,第零个参数是指命令本身(有时也是指shell本身)。你应该使用$1

(("$#" < 1)) && ( (("$1" != 1)) ||  (("$1" -ne 0q)) )

你的布尔逻辑也有点混乱:

(( "$#" < 1 && # If the number of arguments is less than one…
  "$1" != 1 || "$1" -ne 0)) # …how can the first argument possibly be 1 or 0?

这可能就是你想要的:

(( "$#" )) && (( $1 == 1 || $1 == 0 )) # If true, there is at least one argument and its value is 0 or 1

这是一个改进,谢谢。但是它仍然给我错误: ./setTouchpadEnabled: 第2行:((: != 1: 语法错误:需要操作数(错误标记为“!= 1”) ./setTouchpadEnabled: 第2行:((: != 0: 语法错误:需要操作数(错误标记为“!= 0”) - Cheiron
1
引号在 (( )) 内并不是必需的,但它们可以使 StackOverflow 的语法高亮更智能。 - kojiro
@Cheiron,我觉得你误解了我的评论。请再看一下我的回答。 - kojiro
1
哇,我确实在布尔逻辑上犯了错误。但它仍然给我报错: ./setTouchpadEnabled: 第2行:((: 0 && ( == 1 || == 0 ) : 语法错误:需要操作数(错误标记为“== 1 || == 0)”) - Cheiron

8

我知道这个问题已经有答案了,但是我想分享一下我的看法,因为我认为大小写转换是一个被低估的工具(可能是因为人们认为它很慢,但实际上它至少和if语句一样快,有时候甚至更快)。

case "$1" in
    0|1) xinput set-prop 12 "Device Enabled" $1 ;;
      *) echo "This script requires a 1 or 0 as first parameter." ;;
esac

这很好,也很干净。另外,在 case 语句中评估变量是可以安全地不加引号的地方之一。 - SpinUp __ A Davis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接