我试图以纪元形式获取 2 个日期的差异,并将数字转换回天数:
EXPIRYEPOCH=$(date --date="$EXPIRYDATE" +%s)
TODAYEPOCH=$(date --date="$TODAYSDATE" +%s)
DAYSLEFT=$(expr ($EXPIRYEPOCH - $TODAYEPOCH) / 86400 )
DAYSLEFT
上面的计算失败 - 而下面的减法的单个计算成功:
DAYSLEFT=$(expr $EXPIRYEPOCH - $TODAYEPOCH)
用于设置DAYSLEFT
变量(先减后除)的正确格式是什么?
答案1
像这样(不要再使用过时的expr
):
dayleft=$(( arithmetic expression ))
dayleft=$(bc -l <<< "scale=2; 100/3")
正如所述斯蒂芬·查泽拉斯在注释中,ksh93
、zsh
和确实支持和yash
内的浮点数。$((...))
((...))
expr
是古代 shell 代码中用来做数学的程序。在 bash 等 Posix shell 中,使用$(( expression ))
.在 bash、ksh88+、mksh/pdksh 或 zsh 中,您还可以使用(( expression ))
或let expression
((...))
是一个算术命令,如果表达式非零,则返回退出状态 0;如果表达式为零,则返回 1。如果需要副作用(分配),也用作“let”的同义词。看http://mywiki.wooledge.org/ArithmeticExpression
$((...))
是算术替换。完成算术运算后,整个内容将被表达式的值替换。看http://mywiki.wooledge.org/ArithmeticExpression
命令替换:"$(cmd "foo bar")"
导致命令“cmd”使用参数“foo bar”执行,并将"$(..)"
被输出替换。看http://mywiki.wooledge.org/BashFAQ/002和http://mywiki.wooledge.org/CommandSubstitution
避免使用大写变量,它们保留供系统使用
最后
expiryepoch=$(date --date="$expirydate" +%s)
todayepoch=$(date --date="$todaysdate" +%s)
dayleft=$(bc <<< "scale=2; (todayepoch - expiryepoch) / 86400")
答案2
算术扩展的语法是$(( math ))
。所以你expr
在这里根本不需要,你正在寻找的是:
DAYSLEFT=$(( ($EXPIRYEPOCH - $TODAYEPOCH) / 86400 ))
现在,它失败的原因是expr
,虽然 是一个外部程序,可以读取分组表达式,但您需要保护括号免受 shell 的影响。由于括号是 shell 中的保留字符(它们打开和关闭子 shell),因此如果您想传递带括号的语句按原样对于外部命令,您需要转义括号,并在括号两侧留一个空格,以便它们不会与变量连接:
DAYSLEFT=$(expr \( $EXPIRYEPOCH - $TODAYEPOCH \) / 86400 )
或者,您可以将它们分成两个表达式,如下所示:
$ DAYSLEFT=$( expr $(expr $EXPIRYEPOCH - $TODAYEPOCH) / 86400 )
$ echo $DAYSLEFT
947
另请注意,如果运算结果不是整数,则效果不会很好。
答案3
您必须转义括号,并且括号和数字之间必须有空格。否则 shell 会认为在那里启动一个子 shell:
DAYSLEFT=$(expr \( $EXPIRYEPOCH - $TODAYEPOCH \) / 86400 )