【问题标题】:Correct usage of bc in a shell script?在 shell 脚本中正确使用 bc?
【发布时间】:2015-09-11 03:02:42
【问题描述】:

我只是想用 bc 将一些浮点变量相乘:

#!/bin/bash

a=2.77 | bc
b=2.0  | bc

for cc in $(seq 0. 0.001 0.02)
do
    c=${cc} | bc
    d=$((a * b * c)) | bc
    echo "$d" | bc
done

这并没有给我一个输出。我知道这是一个愚蠢的方法,但我尝试了多种 bc 组合(在不同的地方等)但无济于事。

任何帮助将不胜感激!

【问题讨论】:

  • 每次您| bc 时,您都在运行一个 bc 进程。它对之前的bc 进程一无所知。
  • a=2.77 | bc 也毫无意义(我很惊讶它实际上不是语法错误),因为a=2.77 是一个不会为bc 创建输出以供读取和操作的赋值。你需要echo 就像你在echo "$d" | bc 线上一样。
  • @EtanReisner: a=2.77|bc 启动两个子shell,通过管道将第一个的标准输出连接到第二个的标准输入。首先,它将a 设置为2.77 并终止,关闭标准输出。其次,从 stdin 读取会产生(几乎)立即 EOF,因此 bc 什么也不做。结果是非常昂贵的无操作;甚至分配都不会发生在执行的 shell 环境中。但这肯定不是语法错误:“'简单命令'是一系列可选的变量赋值和重定向,以任何顺序,可选后跟单词和重定向”(XCU 2.9.1)跨度>
  • @rici 是的,我了解内部发生的事情(就执行的内容而言)。令我惊讶的是,shell 没有及早注意到缺少命令并选择保释(因为这是命令的不同情况,而不是有命令的情况),但这肯定是初始阶段的额外处理,根本没有必要到那时。
  • @EtanReisner:我认为它不会在不违反 posix 的情况下保释。不要求命令具有命令名称(根据我的引用),并且管道只是由管道分隔的一系列命令。所以这是一个有效的管道。 (我为其他可能阅读评论的人提供了精确机制。我知道你理解它:))

标签: bash shell math bc


【解决方案1】:

要将两个数字直接相乘,您可以执行以下操作:

echo 2.77 * 2.0 | bc

它将产生 2 个位置的结果 - 因子的最大位置。要将它带到更多的地方,比如 5 个,需要:

echo "scale = 5; 2.77 * 2.0" | bc

如果您将数字相乘,每个数字都有很多小数位,这一点就变得更加重要。

正如其他回复所述,bc 不是 bash 的一部分,而是由 bash 运行的命令。因此,您实际上是在 直接 将输入发送到命令 - 这就是您需要 echo 的原因。如果你把它放在一个文件中(例如,命名为“a”),那么你将运行“bc 放入 shell 脚本中,并让命令运行指定段作为其输入;像这样:

cat <<EOF
Input
EOF

...带有限定符(例如,您需要将“”写为“\”)。

在 BC 中离线运行控制流构造可能会出现更多问题。我尝试了以下

echo "scale = 6; a = 2.77; b = 2.0; define f(cc) { auto c, d; c = cc; d = a*b*c; return d; } f(0); f(0.001); f(0.02)" | bc

并出现语法错误(我安装了 GNU-BC 版本)。另一方面,它会在 C-BC 上运行良好

echo "scale = 6; a = 2.77; b = 2.0; define f(cc) { auto c, d; c = cc; d = a * b * c; return d; } f(0); f(0.001); f(0.02)" | cbc

并为您提供预期的结果 - 匹配您引用的示例...列出 6 个位置。

C-BC 就在这里(它在操作上是 GNU-BC 和 UNIX BC 的大型超集,但不是 100% 符合 POSIX):

https://github.com/RockBrentwood/CBC

语法更接近C,所以你也可以写成

echo "scale = 6, a = 2.77, b = 2.0; define f(cc) { return a * b * cc; } f(0); f(0.001); f(0.02)" | cbc

得到相同的结果。所以,作为另一个例子,这个

echo "scale = 100; for (x = 0, y = 1; x < 50; y *= ++x); y" | cbc

会给你 50 阶乘。然而,像 (x = 0, y = 1) 这样的逗号表达式不是 POSIX 强制要求的 bc,因此它不会在其他 bc 方言中运行,比如 GNU BC。

【讨论】:

    【解决方案2】:

    bc 是一个命令行实用程序,而不是 shell 语法中一些晦涩的部分。该实用程序从其标准输入读取数学表达式并将值打印到其标准输出。由于它不是 shell 的一部分,因此无法访问 shell 变量。

    shell 管道运算符 (|) 将一个 shell 命令的标准输出连接到另一个 shell 命令的标准输入。例如,您可以使用管道左侧的echo 实用程序将表达式发送到bc

    echo 2+2 | bc
    

    这将打印 4,因为这里没有比眼睛看到的更多的东西。

    所以我想你想这样做:

    a=2.77
    b=2.0
    for c in $(seq 0. 0.001 0.02); do
      echo "$a * $b * $c" | bc
    done
    

    注意:shell 变量的扩展发生在 shell 处理 echo 的参数时,您可以通过省略 bc 来验证:

    a=2.77
    b=2.0
    for c in $(seq 0. 0.001 0.02); do
      echo -n "$a * $b * $c" =
      echo "$a * $b * $c" | bc
    done
    

    所以bc 只看到数字。

    如果您想将bc 的输出保存在一个变量中,而不是将其发送到标准输出(即控制台),您可以使用正常的命令替换语法:

    a=2.77
    b=2.0
    for c in $(seq 0. 0.001 0.02); do
      d=$(echo "$a * $b * $c" | bc)
      echo "$d"
    done
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-31
      • 1970-01-01
      • 2023-03-20
      相关资源
      最近更新 更多