【问题标题】:printf ignoring format in bashprintf忽略bash中的格式
【发布时间】:2020-09-16 12:58:27
【问题描述】:

这是一个hackerrank问题:

Compute the average

作为一个简短的总结,您需要对预定义的整数个数求和,然后计算平均值并以 3 位精度打印。

我想出了以下代码:

read number_of_ints;
sum=0

for number in $(seq 1 $number_of_ints); do 
    read number
    sum=$(($sum+$number))
done 

printf "%.3f\n" | bc -l <<< $sum/$number_of_ints
printf "%.3f\n" $(echo "$sum/$number_of_ints" | bc -l)

但是,printf "%.3f\n" | bc -l &lt;&lt;&lt; $sum/$number_of_ints 公然忽略了我的格式字符串,只是以 20 位精度输出它。 同时printf "%.3f\n" $(echo "$sum/$number_of_ints" | bc -l) 正是我想要的。

我知道这 20 个精度数字的根源在于 bc -l 预加载了一个数学库,但 printf "%.3f" 不应该仍将其减少到三位数吗?

【问题讨论】:

    标签: bash printf


    【解决方案1】:

    问题是您没有正确使用printfprintf 期望一个格式字符串后跟尽可能多的字符串,它会尝试根据格式合理地解析它们。您提供了一种格式,但没有输入,因此它可能只是将请求的换行符打印到您在其后面设置的管道。

    bc 现在在标准输入上定义了两个流,并且忽略了管道以支持此处的字符串。

    printf "%.3f\n" | bc -l <<< $sum/$number_of_ints # two inputs
    

    参考this post 类似问题。

    ...但是你根本不需要printf。见https://linux.die.net/man/1/bc

    bc -l <<< "scale=3;$sum/$number_of_ints"
    

    事实上,您可以在bc 中编写整个事物

    #!/usr/bin/bc
    print "\nHow many numbers shall we average? "
    scale=3
    cnt=read()
    c=cnt
    while ( c ) {
      c=c-1
      print "\nEnter a number: "
      n=read()
      t=t+n
    }
    print "\nTotal: ", t, "\n"
    print "Average: ", t/cnt, "\n"
    quit
    

    然后运行它。

    $: ./bcavg
    bc 1.06.95
    Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
    This is free software with ABSOLUTELY NO WARRANTY.
    For details type `warranty'.
    
    How many numbers shall we average? 3
    
    Enter a number: 2
    
    Enter a number: 7
    
    Enter a number: 9
    
    Total: 18
    Average: 6.000
    

    【讨论】:

    • 成功了。问完这个问题后不久我就注意到了我的脑残:)
    【解决方案2】:

    给出的代码实际上并没有将bc 的输出传送到printf 的命令行。

    跨越这一差距的一种方法是使用xargs

    bc -l <<<"$sum/$number_of_ints" | xargs printf '%.3f\n'
    

    【讨论】:

    • 这可能会在使用小数点逗号而不是小数点的语言环境中显着失败,例如 fr_FR。请参阅:stackoverflow.com/q/56909523/7939871,具体取决于 printf 实现是否需要 LC_NUMERIC 格式化参数。
    【解决方案3】:

    bash的解决方案,不诉诸bc

    #!/bin/bash
    
    sum=0
    read n
    for ((i = 0; i < n; ++i)); do read m; ((sum += m)); done
    
    sign=1
    if ((sum < 0)); then sign=-1; ((sum = -sum)); fi
    m=$(( (sum * 10000 / n + 5) / 10 ))
    printf '%d.%03d\n' $((m / 1000 * sign)) $((m % 1000))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-16
      • 2016-05-10
      • 2020-02-18
      • 1970-01-01
      相关资源
      最近更新 更多