在Linux shell中如何使用变量进行除法运算?

175

当我在终端运行如下命令时,它会返回一个 expr: non-integer argument 错误。有没有人可以向我解释一下这是什么意思?

$ x=20
$ y=5
$ expr x / y 
expr: non-integer argument

5
尽管有人可能认为这个问题是“RTFM”(请参阅手册)的问题,但它确实是一个有效的shell编程问题。对于那些不需要解除引用(例如Ruby或JavaScript)的语言的使用者来说,这也是一个合理的问题。应该让它保持开放状态。 - Todd A. Jacobs
6
@ShivanRaptor 不,这个话题是在这里很合适的。它涉及Bash编程。Unix/Linux主要用于使用系统而非编程。现在,shell脚本编写跨越了编程和使用系统之间的边界,因此这个问题可以在任何一个站点上讨论。如果有关于“如何设置网络”这样的问题,那肯定属于Unix/Linux。如果是关于Bash交互式按键绑定的问题,那也应该在那里讨论。但是,关于shell脚本编写的问题无论是在这个站点还是另外一个站点都是合适的。 - Brian Campbell
请查看我的答案,其中演示了使用从shell调用Python(将int转换为float)的方法来执行$BASH变量的减法和除法:https://dev59.com/jmsy5IYBdhLWcg3wsADQ#55856163 - Victoria Stuart
6个回答

240

这些变量是Shell变量。要将它们扩展为另一个程序的参数(如expr),您需要使用$前缀:

expr $x / $y

它报错的原因是因为它认为你试图对字母字符(即非整数)进行操作。

如果您正在使用Bash shell,您可以使用表达式语法实现相同的结果:

echo $((x / y))
或者:
z=$((x / y))
echo $z

2
通过阅读bash的man页,您可以了解很多信息。在提示符处键入“man bash”(按“q”退出)。 - paddy
84
需要在此页面的某处注明,大多数(如果不是全部)GNU/Linux shell仅执行整数运算。 - Skippy le Grand Gourou

46

我相信在其他帖子中已经提到过了:

calc(){ awk "BEGIN { print "$*" }"; }

那么你可以简单地输入:

calc 7.5/3.2
  2.34375

在您的情况下,它将是:

x=20; y=3;
calc $x/$y
或者,如果您愿意,将其作为单独的脚本添加并在$ PATH中使其可用,以便您始终可以在本地Shell中使用它:
#!/bin/bash
calc(){ awk "BEGIN { print $* }"; }

11
你可以使用 echo '1 / 3' | bc -l 命令。 - Eugene

26

为什么不使用let呢?我觉得它更容易。 这里有一个你可能会觉得有用的例子:

start=`date +%s`
# ... do something that takes a while ...
sleep 71

end=`date +%s`
let deltatime=end-start
let hours=deltatime/3600
let minutes=(deltatime/60)%60
let seconds=deltatime%60
printf "Time spent: %d:%02d:%02d\n" $hours $minutes $seconds

另一个简单的例子 - 计算自1970年以来的天数:

let days=$(date +%s)/86400

18

引用Bash变量需要参数扩展

大多数Linux发行版的默认shell是Bash。在Bash中,变量必须使用美元符号前缀进行参数扩展。例如:

x=20
y=5
expr $x / $y

当然,Bash也有算术运算符和一个特殊的算术扩展语法,因此无需将expr二进制文件作为单独的进程调用。您可以这样让 shell 完成所有工作:

x=20; y=5
echo $((x / y))

1
请参阅Bash参考手册中的算术扩展Shell算术以获取所有详细信息。 - Todd A. Jacobs
1
这与_dereferencing_无关,而是与_interpolating_有关,而且在2013年不鼓励使用expr - Gilles Quénot
@sputnick,你显然很困惑。请随意查阅字典。参见dereferenceinterpolate - Todd A. Jacobs
我听说“插值”被用来指代其他人可能称之为“参数扩展”的东西。起初,我想说,保持解引用谈论C和C++代码,但是不,他们在Bash世界中也这样说。所以我们都在谈论同一件事情。对反对expr的投票加1。 - Prashant Kumar
1
更好的词是“扩展”,而不是“取消引用”。当我们使用指针时,才会使用“取消引用”,但这里并非如此,这只是简单的变量。 - Gilles Quénot
1
@Prashant:在Bash世界中,tldp并不是一个良好的参考资料。 - Gilles Quénot

7
要获取小数点后面的数字,可以这样做:-
read num1 num2
div=`echo $num1 / $num2 | bc -l`
echo $div

1

让我们假设

x=50
y=5

然后。
z=$((x/y))

这将正常工作。 但是,如果您想在case语句中使用/运算符,则无法解析它。 在此输入代码 在这种情况下,请使用简单的字符串,如div或devide或其他内容。 请参见代码。

这是错误的。/ 作为 shell-case 标签是可以正常工作的。不起作用的是在没有引用的情况下使用 * 进行乘法,这可能是您实际上所做的;_那_会导致它有效地覆盖 case 中后续的所有项,在您的示例中是“devide”和“modulo”。 - dave_thompson_085

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