如何让 bc(1) 打印前导零?

发布于 2024-12-19 19:22:47 字数 232 浏览 1 评论 0原文

我在 Makefile 中执行如下操作:(

echo "0.1 + 0.1" | bc

当然,在实际文件中,数字是动态的)

它打印 .2 但我希望它打印 0.2

我想在不诉诸 sed 的情况下执行此操作,但我似乎找不到如何让 bc 打印零。或者是 bc 无法做到这一点?

I do something like the following in a Makefile:

echo "0.1 + 0.1" | bc

(in the real file the numbers are dynamic, of course)

It prints .2 but I want it to print 0.2.

I would like to do this without resorting to sed but I can't seem to find how to get bc to print the zero. Or is bc just not able to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

你怎么这么可爱啊 2024-12-26 19:22:47

您还可以使用 awk 来格式化:

 echo "0.1 + 0.1" | bc | awk '{printf "%f", $0}'

或使用 awk 本身进行数学计算:

 echo "0.1 0.1" | awk '{printf "%f", $1 + $2}'

You can also resort to awk to format:

 echo "0.1 + 0.1" | bc | awk '{printf "%f", $0}'

or with awk itself doing the math:

 echo "0.1 0.1" | awk '{printf "%f", $1 + $2}'
·深蓝 2024-12-26 19:22:47

这可能对你有用:

echo "x=0.1 + 0.1; if(x<1) print 0; x" | bc

This might work for you:

echo "x=0.1 + 0.1; if(x<1) print 0; x" | bc
誰認得朕 2024-12-26 19:22:47

快速查看 源代码(参见bc_out_num(),第1461行),如果整数部分是0。除非我错过了什么,否则此行为不依赖于可以使用命令行标志更改的参数。

简短回答:不,我认为没有办法让 bc 按照您想要的方式打印数字。

如果您仍想使用 bc,我认为使用 sed 没有任何问题。恕我直言,以下内容看起来并不那么可怕:

[me@home]$ echo "0.1 + 0.1" | bc | sed 's/^\./0./'
0.2

如果您真的想避免 sed,那么 eljunior 的 a> 和 choroba 的 建议非常简洁,但它们需要依赖于值的调整以避免尾随零。这对您来说可能是问题,也可能不是问题。

After a quick look at the source (see bc_out_num(), line 1461), I don't see an obvious way to make the leading 0 get printed if the integer portion is 0. Unless I missed something, this behaviour is not dependent on a parameter which can be changed using command-line flag.

Short answer: no, I don't think there's a way to make bc print numbers the way you want.

I don't see anything wrong with using sed if you still want to use bc. The following doesn't look that ghastly, IMHO:

[me@home]$ echo "0.1 + 0.1" | bc | sed 's/^\./0./'
0.2

If you really want to avoid sed, both eljunior's and choroba's suggestions are pretty neat, but they require value-dependent tweaking to avoid trailing zeros. That may or may not be an issue for you.

错爱 2024-12-26 19:22:47

我在文档中找不到有关输出格式的任何内容。除了 sed,您还可以使用 printf:

printf '%3.1f\n' $(bc<<<0.1+0.1)

I cannot find anything about output format in the documentation. Instead of sed, you can also reach for printf:

printf '%3.1f\n' $(bc<<<0.1+0.1)
空名 2024-12-26 19:22:47

回显“$a / $b”| BC -l | sed -e 's/^-\./-0./' -e 's/^\./0./'

这应该适用于结果为

  • “-.123
  • ” 的所有情况.123"
  • "-1.23"
  • "1.23"

解释:

  1. 对于仅以 -. 开头的所有内容,请将 -. 替换为 -0。

  2. 对于仅以 开头的所有内容。,将 . 替换为 0.

echo "$a / $b" | bc -l | sed -e 's/^-\./-0./' -e 's/^\./0./'

This should work for all cases where the results are:

  • "-.123"
  • ".123"
  • "-1.23"
  • "1.23"

Explanation:

  1. For everything that only starts with -., replace -. with -0.

  2. For everything that only starts with ., replace . with 0.

嘿哥们儿 2024-12-26 19:22:47

基于 potongs 答案 ,

对于分数结果:

echo "x=0.1 + 0.1; if(x<1 && x > 0) print 0; x" | bc -l

请注意,负结果将无法正确显示。 Aquarius Power 有一个解决方案 为此。

Building on potongs answer,

For fractional results:

echo "x=0.1 + 0.1; if(x<1 && x > 0) print 0; x" | bc -l

Note that negative results will not be displayed correctly. Aquarius Power has a solution for that.

战皆罪 2024-12-26 19:22:47

这也将处理负数:

echo "0.1 - 0.3" | bc | sed -r 's/^(-?)\./\10./'

This one will also handle negative numbers:

echo "0.1 - 0.3" | bc | sed -r 's/^(-?)\./\10./'
月下客 2024-12-26 19:22:47

这只使用 bc,并且适用于负数:

bc <<< "x=-.1; if(x==0) print \"0.0\" else if(x>0 && x<1) print 0,x else if(x>-1 && x<0) print \"-0\",-x else print x";

尝试使用:

for y in "0" "0.1" "-0.1" "1.1" "-1.1"; do
  bc <<< "x=$y; if(x==0) print \"0.0\" else if(x>0 && x<1) print 0,x else if(x>-1 && x<0) print \"-0\",-x else print x";
  echo;
done

this only uses bc, and works with negative numbers:

bc <<< "x=-.1; if(x==0) print \"0.0\" else if(x>0 && x<1) print 0,x else if(x>-1 && x<0) print \"-0\",-x else print x";

try it with:

for y in "0" "0.1" "-0.1" "1.1" "-1.1"; do
  bc <<< "x=$y; if(x==0) print \"0.0\" else if(x>0 && x<1) print 0,x else if(x>-1 && x<0) print \"-0\",-x else print x";
  echo;
done
沉溺在你眼里的海 2024-12-26 19:22:47
$ bc -l <<< 'x=-1/2; if (length (x) == scale (x) && x != 0) { if (x < 0) print "-",0,-x else print 0,x } else print x'

这是纯粹的bc。它通过将表达式的length 结果与scale 进行比较来检测前导零。它适用于正数和负数。

$ bc -l <<< 'x=-1/2; if (length (x) == scale (x) && x != 0) { if (x < 0) print "-",0,-x else print 0,x } else print x'

This one is pure bc. It detects the leading zero by comparing the result of the length with the scale of the expression. It works on both positive and negative number.

风启觞 2024-12-26 19:22:47

对于正数,它可能就像打印(字符串)零一样简单:

$ echo '"0";0.1+0.1' | bc
0.2

如果数字大于(或等于)1,则避免使用零:

$ echo 'x=0.1+0.1;  if(x<1){"0"};  x' | bc
0.2

如果数字可能为负数,它会变得有点复杂:

echo 'x= 0.3 - 0.5 ; s=1;if(x<0){s=-1};x*=s;if(s<0){"-"};if(x<1) {"0"};x' | bc
-0.2

您可以定义一个函数并将其添加到库中:

$ echo 'define leadzero(x){auto s;
        s=1;if(x<0){s=-1};x*=s;if(s<0){"-"};if(x<1){"0"};
        return(x)};
        leadzero(2.1-12.4)' | bc
-10.3

$ echo 'define leadzero(x){auto s;
        s=1;if(x<0){s=-1};x*=s;if(s<0){"-"};if(x<1){"0"};
        return(x)};
        leadzero(0.1-0.4)' | bc
-0.3

For positive numbers, it may be as simple as printing (an string) zero:

$ echo '"0";0.1+0.1' | bc
0.2

avoid the zero if the number is bigger (or equal) to 1:

$ echo 'x=0.1+0.1;  if(x<1){"0"};  x' | bc
0.2

It gets a bit more complex if the number may be negative:

echo 'x= 0.3 - 0.5 ; s=1;if(x<0){s=-1};x*=s;if(s<0){"-"};if(x<1) {"0"};x' | bc
-0.2

You may define a function and add it to a library:

$ echo 'define leadzero(x){auto s;
        s=1;if(x<0){s=-1};x*=s;if(s<0){"-"};if(x<1){"0"};
        return(x)};
        leadzero(2.1-12.4)' | bc
-10.3

$ echo 'define leadzero(x){auto s;
        s=1;if(x<0){s=-1};x*=s;if(s<0){"-"};if(x<1){"0"};
        return(x)};
        leadzero(0.1-0.4)' | bc
-0.3
圈圈圆圆圈圈 2024-12-26 19:22:47

也许,bc 并不是现代最好的“台式计算器”。其他语言会给你更多的控制权。以下是打印 (-1.0..+1.0) 范围内的值(带前导零)的工作示例。这些示例使用 bcAWKPython 3,以及 这里字符串语法。

#!/bin/bash

echo "using bc"
time for (( i=-2; i<=+2; i++ ))
   {
   echo $(bc<<<"scale=1; x=$i/2; if (x==0||x<=-1||x>=1) { print x } else { if (x<0) { print \"-0\";-x } else { print \"0\";x } } ")
   }
echo

echo "using awk"
time for (( i=-2; i<=+2; i++ ))
   {
   echo $(echo|awk "{printf \"%.1f\",$i/2}")
   }  
echo

echo "using Python"
time for (( i=-2; i<=+2; i++ ))
   {
   echo $(python3<<<"print($i/2)")
   }

请注意,Python 版本大约慢 10 倍,如果这很重要的话(对于大多数用途来说仍然非常快)。


使用 shbc< 进行任何重要的数学运算/code> 是愚蠢的差事。现在有更好的台式计算器。例如,您可以使用 此处文档 在 Bash 脚本中嵌入并执行 Python 子例程。

function mathformatdemo {
python3<<SCRIPT
import sys
from math import *
x=${1} ## capture the parameter from the shell
if -1<=x<=+1:
    #print("debug: "+str(x),file=sys.stderr)
    y=2*asin(x)
    print("2*asin({:2.0f})={:+6.2f}".format(x,y))
else: print("domain err")
SCRIPT
}

echo "using Python via Here-doc"
time for (( i=-2; i<=+2; i++ ))
   {
   echo $(mathformatdemo $i)
   }

输出:

using Python via Here-doc
domain err
2*asin(-1)= -3.14
2*asin( 0)= +0.00
2*asin( 1)= +3.14
domain err

Probably, bc isn't really the best "bench calculator" for the modern age. Other languages will give you more control. Here are working examples that print values in the range (-1.0..+1.0) with a leading zero. These examples use bc, AWK, and Python 3, along with Here String syntax.

#!/bin/bash

echo "using bc"
time for (( i=-2; i<=+2; i++ ))
   {
   echo $(bc<<<"scale=1; x=$i/2; if (x==0||x<=-1||x>=1) { print x } else { if (x<0) { print \"-0\";-x } else { print \"0\";x } } ")
   }
echo

echo "using awk"
time for (( i=-2; i<=+2; i++ ))
   {
   echo $(echo|awk "{printf \"%.1f\",$i/2}")
   }  
echo

echo "using Python"
time for (( i=-2; i<=+2; i++ ))
   {
   echo $(python3<<<"print($i/2)")
   }

Note that the Python version is about 10x slower, if that matters (still very fast for most purposes).


Doing any non-trivial math with sh or bc is a fool's errand. There are much better bench calculators available nowadays. For example, you can embed and execute Python subroutines inside your Bash scripts using Here Documents.

function mathformatdemo {
python3<<SCRIPT
import sys
from math import *
x=${1} ## capture the parameter from the shell
if -1<=x<=+1:
    #print("debug: "+str(x),file=sys.stderr)
    y=2*asin(x)
    print("2*asin({:2.0f})={:+6.2f}".format(x,y))
else: print("domain err")
SCRIPT
}

echo "using Python via Here-doc"
time for (( i=-2; i<=+2; i++ ))
   {
   echo $(mathformatdemo $i)
   }

Output:

using Python via Here-doc
domain err
2*asin(-1)= -3.14
2*asin( 0)= +0.00
2*asin( 1)= +3.14
domain err
傲世九天 2024-12-26 19:22:47

另一种简单的方法,类似于此线程此处中的一篇文章:

echo 'x=0.1+0.1; print "0",x,"\n"' | bc

打印变量列表,包括前导 0 和换行符。

Another simple way, similar to one of the posts in this thread here:

echo 'x=0.1+0.1; print "0",x,"\n"' | bc

Print the list of variables, including the leading 0 and the newline.

薄暮涼年 2024-12-26 19:22:47

由于您的问题被标记为 [bash],您可以简单地计算答案并使用命令替换将其保存到变量中(例如 r="$(.. .)"),然后使用 [[..]]=~ 来测试结果中的第一个字符是否为 [1- 9] (例如 [[ $r =~ ^[1-9].*$ ]]),如果第一个字符不是,则在 r 的开头添加 '0',例如

编辑,由于 G.Man 的良好捕获...)

r=$(echo "0.1 + 0.1" | bc)             # compute / save result
sign="";                               # set sign to empty str
[[ ${r:0:1} == - ]] && {               # if negative
  sign='-'                             # save - as sign
  r="${r:1}"                           # trim from r
}
[[ $r =~ ^[1-9].*$ ]] || r="0$r"       # test 1st char [1-9] or prepend 0
echo "${sign}$r"                       # output result with sign

结果

0.2

如果结果 r1.0 或更大,则不为零前置,例如(作为 1-liner)

$ r=$(echo "0.8 + 0.6" | bc); sign=""; [[ ${r:0:1} == - ]] && { sign='-'; r="${r:1}"; }; [[ $r =~ ^[1-9].*$ ]] || r="0$r"; echo "${sign}$r"
1.4
$ r=$(echo "0.8 - 0.6" | bc); sign=""; [[ ${r:0:1} == - ]] && { sign='-'; r="${r:1}"; }; [[ $r =~ ^[1-9].*$ ]] || r="0$r"; echo "${sign}$r"
0.2

和处理负值

$ r=$(echo "-0.8 + 0.6" | bc); sign=""; [[ ${r:0:1} == - ]] && { sign='-'; r="${r:1}"; }; [[ $r =~ ^[1-9].*$ ]] || r="0$r"; echo "${sign}$r"
-0.2

Since you have the question tagged [bash] you can simply compute the answer and save it to a variable using command substitution (e.g. r="$(...)") and then using [[..]] with =~ to test if the first character in the result is [1-9] (e.g. [[ $r =~ ^[1-9].*$ ]]), and if the first character isn't, prepend '0' to the beginning of r, e.g.

(edit due to good catch by G.Man...)

r=$(echo "0.1 + 0.1" | bc)             # compute / save result
sign="";                               # set sign to empty str
[[ ${r:0:1} == - ]] && {               # if negative
  sign='-'                             # save - as sign
  r="${r:1}"                           # trim from r
}
[[ $r =~ ^[1-9].*$ ]] || r="0$r"       # test 1st char [1-9] or prepend 0
echo "${sign}$r"                       # output result with sign

Result

0.2

If the result r is 1.0 or greater, then no zero is prepended, e.g. (as a 1-liner)

$ r=$(echo "0.8 + 0.6" | bc); sign=""; [[ ${r:0:1} == - ]] && { sign='-'; r="${r:1}"; }; [[ $r =~ ^[1-9].*$ ]] || r="0$r"; echo "${sign}$r"
1.4
$ r=$(echo "0.8 - 0.6" | bc); sign=""; [[ ${r:0:1} == - ]] && { sign='-'; r="${r:1}"; }; [[ $r =~ ^[1-9].*$ ]] || r="0$r"; echo "${sign}$r"
0.2

and negative values handled

$ r=$(echo "-0.8 + 0.6" | bc); sign=""; [[ ${r:0:1} == - ]] && { sign='-'; r="${r:1}"; }; [[ $r =~ ^[1-9].*$ ]] || r="0$r"; echo "${sign}$r"
-0.2
怎言笑 2024-12-26 19:22:47

根据 cafemike 的回答 和 Martin T. 的评论,我想出了这个解决方案。

f() { printf ' %b' "@" '\n' \
    | bc --mathlib \
    | sed 's/\(^\|[^0123456789]\)\.\([0123456789]\)/\10.\2/g' ; }

f 0 - 1.1
f 0 - 1
f 0 - 0.1
f 0
f 0 + 0.1
f 0 + 1
f 0 + 1.1
f '"pre.fix:";-1/3'
f '"pre.fix: ";-1/3'
f '"pre.fix:";1/3'
f '"pre.fix: ";1/3'

正则表达式的解释。

对于句子开头的点 \. ^\| 不是数字 [^0123456789],进行替换。

\1\( 圆括号 \) 的反向引用。

如果是“句子开头”的情况,则后向引用什么都没有。

如果是“不是数字”的情况,则后向引用是点之前的一个字符。因此,这适用于负号,或空格,或任何符号或字符(只要不是 0-9)。

对于句子中的任何点,它也可以替换为 0。 因此,我添加了另一个反向引用 \。 2 它只会进行替换。如果点后跟一个数字。

Based on cafemike's answer and Martin T.'s comment, i come up with this solution.

f() { printf ' %b' "@" '\n' \
    | bc --mathlib \
    | sed 's/\(^\|[^0123456789]\)\.\([0123456789]\)/\10.\2/g' ; }

f 0 - 1.1
f 0 - 1
f 0 - 0.1
f 0
f 0 + 0.1
f 0 + 1
f 0 + 1.1
f '"pre.fix:";-1/3'
f '"pre.fix: ";-1/3'
f '"pre.fix:";1/3'
f '"pre.fix: ";1/3'

Explanation for the regular expression.

For a dot \. that is at the beginning of the senstence ^ or \| that is not a digit [^0123456789], do the replacement.

\1 is a back reference of the \( round brackets \).

If it is the case of "beginning of the sentence, the back reference is nothing.

If it is the case of "not a digit", the back reference is the one character before the dot. Thus this works for negative sign, or a space, or any symbols or characters (as long as not 0-9).

There is a catch. For any dot within a sentence, it may be replaced with 0. as well. Thus i am adding another back reference \2. It will do the replacement only if the dot is followed by a digit.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文