printf 忽略 bash 中的格式
printf ignoring format in bash
这是一个 hackerrank 问题:
作为一个简短的总结,您需要对预定义数量的整数求和,然后计算平均值并以 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 <<< $sum/$number_of_ints
公然忽略我的格式字符串并简单地以 20 位精度输出它。
同时 printf "%.3f\n" $(echo "$sum/$number_of_ints" | bc -l)
完全按照我的意愿行事。
我知道 20 位精度数字的根源在于 bc -l 预加载了一个数学库,但 printf "%.3f" 不应该仍然将其减少到三位数吗?
给出的代码实际上并未将 bc
的输出传送到 printf
的命令行。
跨越这个差距的一种方法是 xargs
:
bc -l <<<"$sum/$number_of_ints" | xargs printf '%.3f\n'
问题是您没有正确使用 printf
。 printf
需要一个格式字符串,后跟尽可能多的字符串,并尝试根据格式正确地解析它们。您提供了一种格式,但没有输入,因此它可能只是将请求的换行符打印到您在其后面设置的管道中。
bc
现在在 stdin 上定义了两个流,并且忽略管道以支持 here-string。
printf "%.3f\n" | bc -l <<< $sum/$number_of_ints # two inputs
c.f。 类似问题。
...但是您根本不需要 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
纯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))
这是一个 hackerrank 问题:
作为一个简短的总结,您需要对预定义数量的整数求和,然后计算平均值并以 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 <<< $sum/$number_of_ints
公然忽略我的格式字符串并简单地以 20 位精度输出它。
同时 printf "%.3f\n" $(echo "$sum/$number_of_ints" | bc -l)
完全按照我的意愿行事。
我知道 20 位精度数字的根源在于 bc -l 预加载了一个数学库,但 printf "%.3f" 不应该仍然将其减少到三位数吗?
给出的代码实际上并未将 bc
的输出传送到 printf
的命令行。
跨越这个差距的一种方法是 xargs
:
bc -l <<<"$sum/$number_of_ints" | xargs printf '%.3f\n'
问题是您没有正确使用 printf
。 printf
需要一个格式字符串,后跟尽可能多的字符串,并尝试根据格式正确地解析它们。您提供了一种格式,但没有输入,因此它可能只是将请求的换行符打印到您在其后面设置的管道中。
bc
现在在 stdin 上定义了两个流,并且忽略管道以支持 here-string。
printf "%.3f\n" | bc -l <<< $sum/$number_of_ints # two inputs
c.f。
...但是您根本不需要 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
纯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))