最后

最后

我试图以纪元形式获取 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")

正如所述斯蒂芬·查泽拉斯在注释中,ksh93zsh和确实支持和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/002http://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 )

相关内容