首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >运行带有算术运算的脚本时,获取“需要数值参数”

运行带有算术运算的脚本时,获取“需要数值参数”
EN

Stack Overflow用户
提问于 2017-08-19 05:28:54
回答 3查看 41.9K关注 0票数 14

我正在尝试编写一个函数,它应该将hr:min:sec,ms (即15:41:47,757)形式的时间戳转换为毫秒。该函数如下:

代码语言:javascript
复制
#!/bin/sh
mili () {

    hr=$(echo "$1" | cut -c1-2)
    echo "hr is: " $hr
    min=$(echo "$1" | cut -c4-5)
    echo "min is: " $min
    sec=$(echo "$1" | cut -c7-8)
    echo "sec is: " $sec
    ms=$(echo "$1" | cut -c10-12)
    echo "ms is: " $ms
    total=$(($hr \* 3600 + $min \* 60 + $sec) \* 1000 + $ms)

    return "$total"
    #echo "Result is: "$total" "
}

mili $1

但是,当我运行它时:

代码语言:javascript
复制
./mili.sh "15:41:47,757"

我得到以下输出消息:

代码语言:javascript
复制
./mili.sh: command substitution: line 15: syntax error near unexpected token 
`\*'
./mili.sh: command substitution: line 15: `($hr \* 3600 + $min \* 60 + $sec) 
\* 1000 + $ms'
./mili.sh: line 17: return: : numeric argument required

我试过带和不带单引号、双引号和反引号的expr的变体,但似乎永远不能让它来计算算术。我可以确认这样一个简单的命令有效: expr 2*3,但是当我尝试在我的脚本中使用类似的命令时,它失败了。

怎样才能让它简单地计算我的表达式呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-08-19 05:46:51

在算术运算中,*不需要转义。此外,一些括号也遗漏了。因此,请替换:

代码语言:javascript
复制
total=$(($hr \* 3600 + $min \* 60 + $sec) \* 1000 + $ms)

通过以下方式:

代码语言:javascript
复制
total=$((($hr * 3600 + $min * 60 + $sec) * 1000 + $ms))

替代方案

可以简化代码,避免多次调用cut

代码语言:javascript
复制
mili() {
    IFS=':,' read hr min sec ms <<<"$1"
    echo "hr is: " $hr
    echo "min is: " $min
    echo "sec is: " $sec
    echo "ms is: " $ms
    total=$((($hr * 3600 + $min * 60 + $sec) * 1000 + $ms))
    echo "Total=$total"
    return "$total"
}

旁白: Bash算术和美元符号

在Bash算术上下文中,变量前的美元符号是可选的。例如:

代码语言:javascript
复制
$ a=1; echo "$((1 + a)) and $((1+ $a))"
2 and 2

虽然一些风格指南建议在算术上下文中省略$,但有一个关键的区别。正如评论中的Chepner points out所说,对未定义变量的处理方式非常不同:

代码语言:javascript
复制
$ unset a
$ echo $((1 + $a))
bash: 1 + : syntax error: operand expected (error token is "+ ")
$ echo $((1 + a))
1

总而言之:

如果希望未定义的变量缺省为零,则省略$.

如果不希望将未定义的变量替换为任何内容,可能会导致无效的表达式,请包含$.

在外壳函数mili中,未定义的变量hrmin等将指示代码错误,我们可能需要一条错误消息来警告我们,并且我们希望包含$。在其他情况下,默认值为零是合理的,我们不会这样做,并且省略$将是正确的。

票数 10
EN

Stack Overflow用户

发布于 2017-08-19 06:02:37

另外几点:

  1. don't return "$total":返回值是介于0和255之间的整数。当小时/分钟/秒为0809时,您需要echo "$total"
  2. you're出错-- bash将前导为零的数字视为八进制,而8和9是无效的八进制数字。

$ mili 11: 22 : 09 ,456 hr is: 11分is: 22 sec is: 09 ms is: 456 bash:(11 * 3600 +22* 60 + 09:值对于基数来说太大(错误标记为"09")

我会写道:

代码语言:javascript
复制
mili () {     
    IFS=":,." read -r hr min sec ms <<<"$1"
    echo "hr is:   $hr" >&2
    echo "min is:  $min" >&2
    echo "sec is:  $sec" >&2
    echo "ms is:  $ms" >&2
    echo "$(( ((10#$hr * 60 + 10#$min) * 60 + 10#$sec) * 1000 + 10#$ms ))"
}

其中10#强制使用基数为10的数字

然后

代码语言:javascript
复制
$ ms=$(mili 11:22:09.456)
hr is:   11
min is:  22
sec is:  09
ms is:  456

$ echo $ms
40929456
票数 9
EN

Stack Overflow用户

发布于 2017-08-19 06:16:23

这里有一个疯狂的选择:

代码语言:javascript
复制
$ mili () {
    IFS=., read -r time ms <<<"$1"
    ms3=$(cut -c 1-3 <<<"${ms}000")
    echo "$(date -u -d "1970-01-01 $time" +%s)$ms3"
}

$ mili 15:41:47,757
56507757

$ mili 15:41:47,75
56507750

$ mili 15:41:47
56507000
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45765276

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档