标题：bc命令
语法
bc [ -c ] [ -l ] [ File ... ]
描述
bc 命令是一个提供任意精度算术的交互式进程。bc 命令首先读取由 File 参数指定的任一输入文件，然后读取标准输入。输入文件必须是包含 bc 命令能读取并执行的命令序列、语句或函数定义的文本文件。
bc 命令是 dc 命令的预处理程序。除非指定 -c（仅编译）标志，否则它自动调用 dc 命令。如果指定了 -c 标志，则来自 bc 命令的输出转到标准输出。
bc 命令允许您来指定十进制、八进制或十六进制的运算的输入和输出进制。缺省值为十进制。此命令还提供了十进制点符号的比例缩放规定。bc 命令始终使用 .（点号）来表示基数点，而不考虑指定为当前语言环境部分的任何十进制点字符。
bc 命令的语法类似于 C 语言的语法。可以使用 bc 命令通过将 ibase 关键字指定给输入进制而 obase 关键字指定给输出进制来在各进制间转化。2 到 16 的范围对于 ibase 关键字是有效的。obase 关键字的范围从 2 直到 /usr/include/sys/limits.h 文件中定义的 BC_BASE_MAX 值设置的限制。不考虑 ibase 和 obase 的设置，bc 命令将字母 A 到 F 识别为其十六进制值 10 到 15。
bc 命令的输出由读取程序控制。输出由包含所有执行的未赋值表达式的值的一行或多行构成。输出的基数和精度由 obase 和 scale 关键字的值控制。
有关 bc 命令处理来自源文件信息的方式的进一步的信息在以下各节中得到描述：
语法
以下语法描述了 bc 程序的语法，其中 program 代表任何有效的程序：
%token EOF NEWLINE STRING LETTER NUMBER
%token MUL_OP
/* '*', '/', '%' */
%token ASSIGN_OP
/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */
%token REL_OP
/* '==', '<=', '>=', '!=', '<', '>' */
%token INCR_DECR
/* '++', '--' */
%token Define Break Quit Length
/* 'define', 'break', 'quit', 'length' */
%token Return For If While Sqrt
/* 'return', 'for', 'if', 'while', 'sqrt' */
%token Scale Ibase Obase Auto
/* 'scale', 'ibase', 'obase', 'auto' */
%start program
%%
program : EOF
| input_item program
;
input_item : semicolon_list NEWLINE
| function
;
semicolon_list : /* empty */
| statement
| semicolon_list ';' statement
| semicolon_list ';'
;
statement_list : /* empty */
| statement
| statement_list NEWLINE
| statement_list NEWLINE statement
| statement_list ';'
| statement_list ';' statement
;
statement : expression
| STRING
| Break
| Quit
| Return
| Return '(' return_expression ')'
| For '(' expression ';'
relational_expression ';'
expression ')' statement
| If '(' relational_expression ')' statement
| While '(' relational_expression ')' statement
| '{' statement_list '}'
;
function : Define LETTER '(' opt_parameter_list ')'
'{' NEWLINE opt_auto_define_list
statement_list '}'
;
opt_parameter_list:/* empty */
| parameter_list
;
parameter_list : LETTER
| define_list ',' LETTER
;
opt_auto_define_list
: /* empty */
| Auto define_list NEWLINE
| Auto define_list ';'
;
define_list : LETTER
| LETTER '[' ']'
| define_list ',' LETTER
| define_list ',' LETTER '[' ']'
;
opt_argument_list : /* empty */
| argument_list
;
argument_list : expression
| argument_list ',' expression
;
relational_expression
: expression
| expression REL_OP expression
;
return_expression : /* empty */
| expression
;
expression : named_expression
| NUMBER
| '(' expression ')'
| LETTER '(' opt_argument_list ')'
| '-' expression
| expression '+' expression
| expression '-' expression
| expression MUL_OP expression
| expression '^' expression
| INCR_DECR named_expression
| named_expression INCR_DECR
| named_expression ASSIGN_OP expression
| Length '(' expression ')'
| Sqrt '(' expression ')'
| Scale '(' expression ')'
;
named_expression : LETTER
| LETTER '[' expression ']'
| Scale
| Ibase
| Obase
;
词法约定
以下词法约定适用于 bc 命令：
1. bc 命令识别最长的可能的词法标记或在给定点开始的定界符。
2. 以 /*（斜杠、星号）开始并以 */（星号、斜杠）结束的注释。注释仅对定界词法标记有效。
3. 将换行字符识别为 NEWLINE 标记。
4. STRING 标记表示一个字符串常量。字符串以 "（双引号）开头并以 "（双引号）终止。引号间的所有字符都按照字面取出。无法指定包含 "（双引号）的字符串。每个字符串的长度限制为 limits.h 文件中定义的 BC_STRING_MAX 值设置的最大字节数。
5. 空白字符仅当出现在 STRING 标志中或用来定界词法标记时才有效。
6. \n（反斜杠、换行）字符：
* 定界词法标记。
* 解释为 STRING 标记中的一个字符序列。
* 当作为多行 NUMBER 标记的一部分时被忽略。
7. NUMBER 标记使用以下语法：
NUMBER : integer
| '.' integer
| integer '.'
|integer '.' integer
;
integer : digit
| integer digit
;
digit : 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
| 8 | 9 | A | B | C | D | E | F
;
NUMBER 标记在 ibase 内部寄存器值指定的进制中解释为数字。
8. NUMBER 标记的值解释为由 ibase 内部寄存器的值指定的进制的数字。每个数字字符具有值 0 到 15（以这里列出的顺序排列），且句号字符表示基点。如果数字大于或等于出现在标记中的 ibase 寄存器的值，则行为未定义。对于指定给 ibase 和 obase 寄存器自己的单个位数的值，有一个例外。
9. 将以下关键字识别为标记：
auto for length return sqrt
break ibase obase scale while
define if quit
10. 除了在关键字中，以下任何字母都看作是一个 LETTER 标记：
a b c d e f g h i j k l m n o p q r s t u v w x y z
11. 将以下单字符和双字符序列识别为 ASSIGN_OP 标记：
* =（等号）
* +=（加号、等号）
* -=（减号、等号）
* *=（星号、等号）
* /=（斜杠、等号）
* %=（百分号、等号）
* ^=（插入记号、等号）
12. 将以下单字符识别为 MUL_OP 标记：
* *（星号）
* /（斜杠）
* %（百分号）
13. 将以下单字符和双字符序列识别为 REL_OP 标记：
* ==(双等号）
* <=（小于号、等号）
* >=（大于号、等号）
* !=（感叹号、等号）
* <（小于号）
* >（大于号）
14. 将以下双字符序列识别为 INCR_DECR 标记：
* ++（双加号）
* --（双连字符）
15. 将以下单字符识别为标记。标记和字符具有相同的名称：
<newline>
(（左圆括号）
)（右圆括号）
,（逗号）
+（加号）
-（减号）
;（分号）
[（左方括号）
]（右方括号）
^ (插入记号)
{ (左花括号)
} (右花括号)
16. 当到达输入末尾时，返回 EOF 标记。
标识符和运算符
bc 命令可识别的标识符有三种：普通标识符、数组标识符和函数标识符。所有三种类型包含单个小写字母。数组标识符后跟 [ ]（左和右方括号）。除了在参数中或自动列表中，数组下标是必需的。数组是单维构成的，且最多可包含 BC_DIM_MAX 值指定的数量。索引从 0 开始。所以数组从 0 开始建立索引值到 BC_DIM_MAX -1 定义的值。下标截断为整数。函数标识符必须后跟 ( )（左和右圆括号）并可能包含自变量。这三种标识符不冲突。
bc 程序表的运算符总结了优先规则和所有运算符的关联性的规则。同一行上的运算符具有相同的优先权。行以递减优先顺序排列。
bc 程序中的运算符
运算符 关联性
++, - - 不适用
unary - 不适用
^ 从右至左
*, /, % 从左至右
+,二进制 - 从左至右
=, +=, -=, *=, /=, ^= 从右至左
==, <=, >=, !=, <, > 无
每个表达式或命名表达式具有一个小数位，它是表达式小数部分要保留的十进制数字的位数。
命名表达式是存储值的位置。命名表达式在赋值的左边是有效的。命名表达式的值是存储于指定位置的值。简单的标识符和数组元素是命名表达式；它们具有一个为零的初始值和一个为零的初始小数位。
内部寄存器 scale、ibase 和 obase 都是命名表达式。包含这些寄存器之一的名称的表达式的小数位是 0。指定给这些寄存器任意之一的值将截断为整数。scale 寄存器包含一个用于计算表达式小数位的全局值（如下描述）。scale 寄存器的值限制为 0 <= scale <= 并具有一个缺省值 0。ibase 和 obase 寄存器分别是输入和输出数字的基数。ibase 的值限制为 2 <= ibase <= 16。obase 的值限制为 2 <= obase = 。
当为 ibase 或 obase 寄存器指定了“词法约定”中描述的列表中的单个位数的值时，该值假定为十六进制。例如：
ibase=A 
设置到底数十，而不考虑当前的 ibase 寄存器值。其它情况下，如果数字大于或等于出现在输入中的 ibase 寄存器的值，则行为未定义。ibase 和 obase 寄存器都具有初始值 10。
内部计算就像十进制（不考虑输入和输出底数）一样进行到指定的小数位个数。当没有得到精确的结果，例如：
scale=0; 3.2/1
bc 命令截断此结果。
obase 寄存器的所有数字值根据以下规则输出：
1. 如果值小于 0，输出 -（连字符）。
2. 输出以下内容之一，这取决于数字值：
* 如果数字值的绝对值大于或等于 1，则输出作为适合 obase 寄存器的一系列数字的值的整数部分（在步骤 3 中描述）。下一步输出最重要的非零数字，每个数后跟连续的较不重要的数字。
* 如果数字值的绝对值小于 1 但大于 0，且数字值的小数位大于 0，则不指定是否输出字符 0。
* 如果数字值是 0，则输出字符 0。
3. 如果该值的小数位大于 0，则输出 .（点号）后跟一系列适合以下 obase 寄存器值的数字。这些数字表示值的小数部分的最重要的部分，且 s 表示正在输出的值的小数位：
* 如果 obase 值是 10，则输出 s 位的数字。
* 如果 obase 值大于 10，输出小于或等于 s 位的数字。
* 如果 obase 值小于 10，则输出大于或等于 s 位的数字。
* 对于值不是 10 的 obase 值，这应该是要表示 10 的精度所需的数位。
* 对于值为 2 到 16 的 obase 值，有效的数字是单字符的第一个 obase：
0 1 2 3 4 5 6 7 8 9 A B C D E F
这分别表示值 0 到 15。
* 对于大于 16 的底数，每个数字写作分开的多位数的十进制数字。除了最重要的小数数字，每个数字前有一个空格字符。对于底数 17 到 100，bc 命令写二位十进制数字，对于底数 101 到 1000，bc 命令写三位的十进制数。例如，底数 25 的十进制数 1024 将写作：
01 15 24
底数 125，如：
008 024
超大数字分行分割，在 POSIX 语言环境中每行 70 个字符。其它语言环境可能在不同的字符边界分割。要继续的行必须以 \ (反斜杠) 结束。
表达式
数字常量是一个表达式。小数位是表示常量的输入中的小数点后面的数位，或 0（如果没有小数点）。
序列（expression）是具有和 expression 相同值和小数位的表达式。括号可以用来更改正常的优先顺序。
一元和二元运算符具有以下语义：
-expression 结果是表达式的负数。结果的小数位是表达式的小数位。
一元增量和减量运算符不会修改它们运算的命名表达式的小数位。结果的小数位是该命名表达式的小数位。
++named_expression 命名表达式按 1 递增。结果就是增量后的命名表达式的值。
- -named_expression 命名表达式按 1 递减。结果就是减量后的命名表达式的值。
named_expression++ 命名表达式按 1 递增。结果就是增量前的命名表达式的值。
named_expression- - 命名表达式按 1 递减。结果就是减量前的命名表达式的值。
乘方运算符 ^ (插入记号) 从右至左绑定。
expression ^expression 结果是 expression 升到第二个 expression 的乘幂。如果第二个表达式不是整数，则行为未定义。如果 a 是左边表达式的小数位且 b 是右边表达式的绝对值，则结果的小数位是：
if b >= 0 min(a * b, max(scale, a))
if b < 0 scale
乘法运算符 *（星号）、/（斜杠）和 %（百分号）从左至右绑定。
expression * expression 结果是两个表达式的乘积。如果 a 和 b 是两个表达式的小数位，则结果的小数位是：
min(a+b,max(scale,a,b))
expression / expression 结果是两个表达式的商。结果的小数位是 scale 的值。
expression % expression 对于表达式 a 和 b，a % b 等同以下步骤来求值：
1. 计算 a/b，保留当前小数位。
2. 请使用结果来计算：
a - (a / b) * b
至小数位：
max(scale + scale(b), scale(a))
结果的小数位将是：
max(scale + scale(b), scale(a))
当 scale 为零时，% 运算符是数学余数运算符。
加法运算符 +（加号）和 -（减号）从左至右绑定。
expression + expression 结果是两个表达式的和。结果的小数位是表达式的小数位的最大值。
expression - expression 结果是两个表达式的差。结果的小数位是表达式的小数位的最大值。
以下赋值运算符从右到左绑定：
* =（等号）
* +=（加号、等号）
* -=（减号、等号）
* *=（星号、等号）
* /=（斜杠、等号）
* %=（百分号、等号）
* ^=（插入记号、等号）
named-expression = expression 这个表达式最终将右边的表达式的值指定给左边的命名表达式。命名表达式和结果的小数位都是表达式的小数位。
复合赋值格式：
named-expression <operator >= expression
等同于：
named-expression = named-expression <operator > expression
除了命名表达式仅求值一次。
与其它所有运算符不同，以下关系运算符仅作为 if 或 while 语句的对象或在 for 语句中时才有效：
* <（小于号）
* >（大于号）
* <=（小于号、等号）
* >=（大于号、等号）
* ==（双等号）
* !=（感叹号、等号）
expression1 < expression2 如果 expression1 的值严格小于 expression2 的值，则关系为真。
expression1 > expression2 如果 expression1 的值严格大于 expression2 的值，则关系为真。
expression1 <= expression2 如果 expression1 的值小于或等于 expression2 的值，则关系为真。
expression1 >= expression2 如果 expression1 的值大于或等于 expression2 的值，则关系为真。
expression1 == expression2 如果 expression1 的值和 expression2 的值相等，则关系为真。
expression1 != expression2 如果 expression1 的值和 expression2 的值不相等，则关系为真。
语句
当语句是一个表达式时，除非主运算符是一个赋值，否则语句的执行写出表达式的值后跟一个换行字符。
当语句是一个字符串时，语句的执行写出字符串的值。
以分号或换行字符隔开的语句按序执行。在 bc 命令的交互式调用中，每次读取一个满足语法生成的换行字符：
input_item : semicolon_list NEWLINE
构成 semicolon_list 的语句的有序列表将立即执行，且该执行产生的任何输出写出时没有任何缓冲区延迟。
如果是 if 语句（if (relation) statement），则当关系为真时执行该 statement。
while 语句（while (relation) statement）实现其中测试 relation 的循环。每次 relation 为真时，则执行statement 并测试 relation。当 relation 为假时，执行在 statement 之后恢复。
for 语句（for (expression; relation; expression) statement）与下面形式相同：
first-expression
while (relation) {
statement
last-expression
}
所有三个表达式都必须存在。
break 语句使 for 或 while 语句终止。
auto 语句（auto identifier [,identifier ] ...）使标识符的值减小。标识符可以是普通标识符或数组标识符。数组标识符由后跟空的方括号的数组名指定。auto 语句必须是在函数定义中的第一个语句。
define 语句：
define LETTER ( opt_parameter_list ) {
opt_auto_define_list
statement_list
}
定义名为 LETTER 的函数。如果先前定义了 LETTER 函数，则 define 语句取代先前的定义。表达式：
LETTER ( opt_argument_list )
调用 LETTER 函数。如果调用中自变量的数量与定义中参数的数量不匹配，则行为未定义。在调用函数之前先定义它。函数看作是在它自己主体内定义，这样循环调用就是有效的。当调用函数时，函数内数字常量值以 ibase 寄存器的值指定的底数来解释。
return 语句（return 和 return (expression)）使函数终止，弹出它的 auto 变量，并指定函数的结果。第一个格式等同于返回 0。函数的调用的值和小数位是括号中表达式的值和小数位。
quit 语句（quit）在输入中的语句出现位置停止 bc 程序的执行，即使它出现在函数定义中或出现在 if、for 或 while 语句中。
函数调用
函数调用由函数名称，后跟包含在括号内的以逗号隔开的表达式列表（这些表达式是函数自变量）组成。作为自变量传递的整个数组由后跟 [ ]（左方括号和右方括号）的数组名称指定。所有函数自变量按值传递。所以对形式参数的更改不会影响实际参数的效果。如果函数通过执行 return 语句终止，则函数的值是 return 语句的圆括号中的表达式的值，或如果不提供表达式或没有 return 语句则为零。
sqrt(expression) 的结果是表达式的平方根。结果在最不重要的小数位置截断。结果的小数位是表达式的小数位或 scale 的值中较大的一个。
length(expression) 的结果是表达式中重要十进制数的总数。结果的小数位是 0。
scale(expression) 的结果是表达式的小数位。结果的小数位是 0。
bc 程序中仅有两种存储类，即全局和自动（本地）。只有对函数而言是本地的标识符需要用 auto 关键字说明。函数的自变量对函数而言是本地的。所有其它标识符假定为全局并可用于所有函数。所有标识符，全局和本地，具有初始值 0。声明为 auto 的标识符在进入函数时分配并在从函数返回时释放。所以它们不在函数调用之间保留值。auto 数组由后跟 []（左方括号、右方括号）的数组名指定。进入函数时，作为参数和自动变量出现的名称的旧值被推上堆栈。函数返回之前，对这些名称的引用仅引用新值。
在那些函数之一使用本地变量的同一个名称之前，从此函数调用的其它函数对这些名称中的任何一个的引用也引用新值。
-l 数学库中的函数当指定 -l 标志时，定义以下函数：
s(expression) 指定 expressionx 的正弦，其中 expression 是弧度。
c(expression) 指定 expressionx 的余弦，其中 expression 是弧度。
a(expression) 指定 expressionx 的反正切，其中 expression 是弧度。
l(expression) 指定 expression 的自然对数。
e(expression) 指定 expression 的幂。
j(expression,expression)
指定整数顺序的 Bessel 函数。
当调用函数时，对这些函数的每一个的调用的小数位是 scale 关键字的值。如果用数学函数域之外的自变量来调用这些函数中的任何一个，则行为未定义。
标志
-c 编译 File 参数，但不调用 dc 命令。
-l （小写 L）定义数学函数的库，并将 scale 变量设置为 20。
退出状态
该命令返回以下退出值：
0 成功完成。
1 遇到语法错误或不能访问输入文件。
unspecified 有其它错误发生。
示例
1. 可以使用 bc 命令作为计算器。根据您是否设置了 scale 变量以及设置了什么值，系统显示小数数量。请输入：
bc
1/4
仅显示 0。要设置 scale 变量并添加注释，请输入：
scale = 1 /* Keep 1 decimal place */
1/4
屏幕显示 0.2。输入：
scale = 3 /* Keep 3 decimal places */
1/4
显示 0.250。输入：
16+63/5
显示 28.600。输入：
(16+63)/5
显示 15.800。输入：
71/6
显示 11.833。
当按下 Enter 键时，bc 命令显示除了赋值以外的每个表达式的值。
当从键盘直接输入 bc 命令表达式，请按文件结束符（Ctrl-D）按键顺序来结束 bc 命令会话并返回至 shell 命令行。
2. 要编写并运行类似 C 语言的程序，请输入类似于以下命令的命令：
bc -l prog.bc
e(2) /* e squared */
ma
屏幕显示 7.38905609893065022723。如果输入：
f(5) /* 5 factorial */
屏幕显示 120。如果输入：
f(10) /* 10 factorial */
屏幕显示 3628800。
此序列解释保存在 prog.bc 文件中的 bc 程序，并从键盘读取更多的 bc 命令语句。用 -l 标志启动 bc 命令将使数学库可用。此示例使用来自数学库中的 e（幂）函数，且 f 在 prog.bc 程序文件中定义为：
/* compute the factorial of n */
define f(n) {
auto i, r;
r = 1;
for (i=2; i<=n; i++) r =* i;
return (r);
}
跟在 for 或 while 语句后的语句必须在同一行开始。当从键盘直接输入 bc 命令表达式时，请按文件结束符（Ctrl-D）按键顺序来结束 bc 命令会话并返回至 shell 命令行。
3. 要将中缀表达式转换为“逆向 Polish 表示法”（Reverse Polish Notation，RPN），请输入：
bc -c
(a * b) % (3 + 4 * c)
屏幕显示：
lalb* 3 4lc*+%ps.
此序列将 bc 命令中缀表示表达式编译为 dc 命令可以解释的表达式。dc 命令对扩展 RPN 表达式求值。在编译后的输出中，每个变量名称前的 l 是将变量的值装入到堆栈上的 dc 子命令。p 显示在堆栈顶端的值，s. 通过将顶端的值存储在寄存器 .（点）来废弃它。可以将 RPN 表达式保存在文件中以使 dc 命令以后通过重定向此命令的标准输出来求值。当从键盘直接输入 bc 命令表达式，请按文件结束符（Ctrl-D）按键顺序来结束 bc 命令会话并返回至 shell 命令行。
4. 要在 shell 中将 pi 的前 10 位数的近似值指定给变量 x，请输入：
x=$(printf "%s\n" 'scale = 10; 104348/33215' | bc)
以下 bc 程序将 pi 的相同近似值（带有标号）打印到标准输出：
scale = 10
"pi equals "
104348 / 33215
5. 要定义一个函数来计算幂函数（如果指定了 -l（小写 L）选项则此类函数为预定义的）的近似值，请输入：
scale = 20
define e(x){
auto a, b, c, i, s
a = 1
b = 1
s = 1
for (i = 1; 1 == 1; i++){
a = a*x
b = b*i
c = a/b
if (c == 0) {
return(s)
}
s = s+c
}
}
要打印前 10 个整数的幂函数的近似值，请输入：
for (i = 1; i <= 10; ++i) {
e(i)
}
文件
/usr/bin/bc 包含 bc 命令。
/usr/lib/lib.b 包含数学库。
/usr/bin/dc 包含桌面计算器。