1. 程式人生 > >Linux基礎命令---bc

Linux基礎命令---bc

bc

  bc是一種算數語言,其語法和c語言類似,可以互動執行。通過命令列選項可以獲得一個標準的數學庫。如果請求,在處理任何檔案之前定義數學庫。BC從處理所有檔案的程式碼開始。命令列中列出的檔案按所列順序排列。在處理完所有檔案後,BC從標準輸入中讀取。所有程式碼都在讀取時執行。(如果檔案包含停止處理器的命令,BC將永遠不會從標準輸入中讀取。

  此命令的適用範圍:RedHat、RHEL、Ubuntu、CentOS、SUSE、openSUSE、Fedora。

1、語法

     bc  [ -hlwsqv ]  [long-options]  [  file ... ] 

           

2、選項列表

選項

說明

-h | --help

幫助資訊

-v | --version

顯示命令版本資訊

-l | --mathlib

定義標準數學庫

-i | --interactive

強制互動

-w | --warn

顯示POSIX的警告資訊

-s | --standard

使用POSIX標準來處理

-q | --quiet

不顯示歡迎資訊

 

3、說明

  1)資料

  bc中最基本的元素是數字。數字是任意精度的數字。這種精度既包括整數部分,也包括分數部分。所有的數字在內部用十進位制表示,所有的計算都用十進位制來表示。(此版本截斷除法和乘運算的結果。)數字有兩個屬性:長度和小數位。長度是數字中有效位的總數,小數位是小數點之後的的有效位數。例如,0.000001的長度是6,小數位是6;1935.000的長度是7,小數位是3。

  2)變數

  數字儲存在兩種型別的變數中,簡單變數和陣列。變數名稱以字母開頭,後面跟著任意數量的字母、數字和下劃線。所有字母都必須小寫。(全字母-數字名是副檔名。在POSIX bc中,所有名稱都是一個小寫字母。)變數的型別在上下文中是明確的,因為所有陣列變數名稱後面都會有方括號([])。

有四個特殊的變數:scale、ibase、obase和last。scale定義了一些操作在小數點之後是如何使用數字的,預設值是0。ibase和obase定義輸入和輸出數字的轉換基。預設值都是基數10。last(擴充套件)是一個變數。它是最後列印的數字的值。所有這些變數可能都有分配給它們的值,以及表示式中使用的值。

  3)註釋

  bc中的註釋以字元“/*”開頭,以字元“*/”結尾。註釋可以從任何地方開始,並顯示為輸入中的單個空格。(這會導致註釋分隔其他輸入項。例如,在變數名的中間找不到註釋。)註釋包括註釋開始和結束之間的任何新行(行尾)。

為了支援bc指令碼的使用,添加了行註釋作為擴充套件。行註釋從“#”字元開始,繼續到行的結束。行結束字元不是註釋的一部分,而是正常處理的。

如果命令列上的任何檔案無法開啟,bc將報告該檔案不可用並終止。

4、關於表示式

  這些數字由表示式和語句操作。由於語言設計為互動式,所以語句和表示式會盡快執行。沒有“主”程式,而是在遇到時執行程式碼。

一個簡單的表示式只是一個常量。BC使用變數ibase指定的當前輸入基將常量轉換為內部十進位制數。(函式中有一個例外。)ibase的有效值為2到16,將超出此範圍之後,分配給ibase的值可能是2或16。輸入數字可能包含字元0-9和A-F。(注:它們必須是大寫字母,小寫字母是變數名稱。)無論ibase的值是多少,單數數字總是有該數字的值。(即A=10。)對於多位數字,bc將所有大於或等於ibase的輸入數字更改為IBASE-1的值。這使得FFF始終輸入的最大3位數。

  完全表示式類似於許多其他高階語言。由於只有一種數字,所以沒有混合型別的規則。相反,有關於表示式精度的規則。每個表示式都有一個精度。這是從原始數字的精度、所執行的操作以及在許多情況下變數scale的值匯出的。變數scale的有效值為0到可由c語言整數表達的最大值。

  在以下合法表示式的描述中,“expr”指的是一個完整的表示式,“var”指的是一個簡單的或陣列變數。除非特別提到,結果的精度是所涉及的表示式的最大精度。

普通表示式

說明

-expr

結果是對錶達式的否定。

++var

變數增加1,而新值是表示式的結果

--var

變數減1,而新值是表示式的結果

var++

表示式的結果是變數的值,然後變數增加1

var--

表示式的結果是變數的值,然後變數減1

expr * expr

表示式的結果是這兩個表示式的乘積

expr + expr

表示式的結果是這兩個表示式的和

expr – expr

表示式的結果是這兩個表示式的差

expr / expr

表示式的結果是這兩個表示式的商。結果的精度是變數scale的值。

expr % expr

表示式的結果是“餘數”

expr ^ expr

表示式的結果是n次方,第二個表示式必須是整數。如果指數是負數,那麼結果的精度是scale

(expr)

強制對錶達式進行計算

var = expr

變數就是表示式的值

var <op>= expr

相當於“var=var<op>expr”,例如”var -= expr” 等價於“var=var-expr”

關係表示式

關係表示式是一種特殊的表示式,計算結果總是0或1。如果關係為真,則計算為1;如果關係為假,則結果是0.。這些表示式可能出現在任何合法表示式中。(POSIX bc要求關係表示式僅用於if、while和語句,並且只能在其中進行一次關係測試。)

expr1 < expr2

 

     

關係表示式

關係表示式是一種特殊的表示式,計算結果總是0或1。如果關係為真,則計算為1;如果關係為假,則結果是0.。這些表示式可能出現在任何合法表示式中。(POSIX bc要求關係表示式僅用於if、while和語句,並且只能在其中進行一次關係測試。)

expr1 < expr2

expr1 <= expr2

expr1 > expr2

expr1 >= expr2

expr1 == expr2

expr1 != expr2

expr1 && expr2

expr1 || expr2

!expr

 

 

 

 

     運算子的優先順序如下,從上到下依次增加:

運算子

結合方式

||

左結合

&&

左結合

不結合

關係運算符

左結合

賦值運算子

右結合

+和-

左結合

*、/、%

左結合

^

右結合

一元運算子 -

不結合

++和--

不結合

選擇此優先順序是為了使符合POSIX的bc程式能夠正確執行。這將導致關係運算符和邏輯運算子在與賦值表示式一起使用時有一些不尋常的行為。例如下面的表示式:

a = 3<5

  大多數C程式設計師會假設這會將“3<5”(值1)的結果賦給變數“a”,這在bc中所做的是將值3賦給變數“a”,然後比較3到5。在使用關係運算符和邏輯運算子與賦值運算子時,最好使用括號。

  在bc中還提供了一些特殊的表示式。這些表示式與使用者定義的函式和標準函式有關。它們都以“名稱(引數)”的形式出現。有幾個標準函式:

  1)length(expr),計算表示式結果的有效位數。

  2)read(),Read函式(一個擴充套件)將從標準輸入中讀取一個數字,而不管該函式發生在何處。注意,這可能會導致標準輸入中的資料和程式混合出現問題。這個函式的最佳使用是在一個已經編寫好的程式中,這個程式需要使用者輸入,但絕不允許從使用者輸入程式程式碼。讀函式的值是從標準輸入中讀取的數字,使用轉換基的變數ibase的當前值。

  3)scale ( expr ),這個函式的值是expr表示式中小數點之後的位數。

  4)sqrt ( expression ),函式的結果是表示式的開方值。

 

5、關於語句

     語句(在大多數代數語言中)提供表示式計算的順序。在bc中,語句被“儘快”執行。執行發生在遇到的換行符的時候,並且有一個或多個完整的語句。由於這種立即執行,換行符在bc中非常重要。事實上,分號和換行符都用作語句分隔符。如果換行符放置不當,將導致語法錯誤。因為換行符是語句分隔符,所以可以使用反斜槓字元隱藏換行符。(<nl>)在bc中顯示為空格而不是新行。語句列表是由分號和換行符分隔的一系列語句。

     1)表示式

     這條語句做兩件事之一。如果表示式以“<變數><賦值>.”開頭,則被認為是賦值語句。如果表示式不是賦值語句,則計算表示式並將表示式列印到輸出。在列印數字之後,將列印換行符。例如,“a=1”是一個賦值語句和“(a=1)”是一個具有內嵌賦值的表示式。輸出基obase的有效值是2~BC_BASE_MAX。對於基數2至16,通常採用書寫數字的方法。對於大於16的基數,bc使用多字元數字方法將每個較高的基數列印成以10為基數的資料。由於數字具有任意精度,一些數字可能無法在一條輸出線上列印。這些長數字將被分割,以“\”作為一行上的最後一個字元,每行列印的最大字元數為70個。由於bc的互動性,列印一個數字會導致最後將列印值賦值給特殊變數“last”的副作用。這允許使用者恢復列印的最後一個值,而不必重新鍵入列印數字的表示式。將last變數賦值為“最後一個值”是合法的,並將最後一個列印的值用指定的值覆蓋。新賦值將保持不變,直到列印下一個數字或將另一個值分配給“last”為止。

     2)字串

  字串被列印到輸出。字串以雙引號開始,包含所有字元直到下一個雙引號字元。所有字元都是字面意思,包括任何換行符。字串後不列印換行符。

     3)列印列表

  print語句(擴充套件)提供了另一種輸出方法。“list”是由逗號分隔的字串和表示式的列表。每個字串或表示式都按列表的順序列印。不列印終止換行符。表示式的將被計算出值,最後將其值列印並分配給變數“last”。列印語句中的字串將列印到輸出中,並可能包含特殊字元。特殊字元以反斜槓字元“\”開始。bc識別的特殊字元是“a”(警報或鍾)、“b”(反斜槓)、“f”(表單提要)、“n”(換行符)、“r”(回車)、“q”(雙引號)、“t”(製表符)和“\”(反斜槓)。反斜槓後面的任何其他字元都將被忽略。

     4)語句列表

     這是複合語句。它允許將多個語句組合在一起執行。

     5)if (表示式)  statement 1  [else statement 2]

     if語句根據表示式的值決定執行statement 1或statement 2。如果表示式為非零,則執行statement 1。如果存在statement 2,且表示式的值為0的時候執行statement 2。

  6)while ( expression )  statement

     while語句將在表示式為非零時執行語句。它在每次執行語句之前計算表示式。迴圈的終止是由零表示式值或break語句的執行引起的。

     7)for ( [expression1] ; [expression2] ; [expression3] )  statement

     for語句控制語句的重複執行。表示式1是在迴圈之前計算的。表示式2是在每次語句執行之前計算的。如果表示式2為非零,則計算語句;如果為零,則終止迴圈。每次執行語句後,計算表示式3。在重新計算表示式2之前,如果未找到表示式1或表示式3,則不會在計算值的點上對其進行任何計算。

     8)break

     break語句用來強制退出,通常用在for語句或者while語句中。

     9)continue

     continue語句用來結束本次迴圈。

     10)halt

     halt語句會導致bc程式退出。

     11)return

     函式返回0.

     12)return expr

     返回表示式的值。

     13)偽語句,這些語句不會執行,他們在編譯的時候才會起作用。下面列出偽語句

           a)limits,列印由於bc版本而產生的限制

           b)quit,遇到quit指令的時候就會退出bc,無論它出現在什麼地方。例如“if (0 == 1) quit”就會導致退出bc

           c)warranty,列印較長的授權通知

6、函式

     1)函式

     bc中的函式總是計算一個值並將其返回給呼叫者。函式定義是“動態的”,在輸入中遇到定義之前,函式是未定義的。然後使用該定義,直到遇到相同名稱的另一個定義函式。然後,新定義取代舊的定義。函式定義方式如下:

           define name ( parameters ) { newline

            auto_list  statement_list }

函式的呼叫很簡單“name(parameters)”。

     2)引數

     引數是數字或陣列。在函式定義中,可以有0個或者多個引數,通過逗號分隔開。所有引數都是通過值引數呼叫的。陣列是通過符號“name[]在引數定義中指定的。在函式呼叫中,實參是數字引數的完整表示式。相同的符號。陣列的定義和傳值使用相同的符號。命名陣列通過值傳遞給函式。由於函式定義是動態的,因此在呼叫函式時會檢查引數號和型別。引數數量或型別的不匹配都會導致執行時錯誤。對未定義函式的呼叫也會出現執行時錯誤。

     3)auto_list

“auto_list”是供“本地”使用的變數的可選列表。auto_list的語法(如果存在)是“autoname,…;”。(分號是可選的。)每個名稱都是自動變數的名稱。陣列可以使用與引數相同的表示法來指定。這些變數的值在函式開始時被推入堆疊中。然後將變數初始化為零,並在函式的整個執行過程中使用。在函式退出時,這些變數被彈出,以便恢復這些變數的原始值(在函式呼叫時)。這些引數實際上是自動變數,它們被初始化為函式呼叫中提供的值。自動變數不同於傳統區域性變數,因為如果函式A呼叫函式B,B可以使用相同的名稱訪問函式A的自動變數,除非函式B呼叫它們為自動變數。由於自動變數和引數被推到堆疊上,bc支援遞迴函式。

     4)函式體

函式體是一系列bc語句的列表。同樣,語句用分號或換行符分隔。返回語句導致函式的終止和值的返回。返回語句有兩個版本。第一個形式“return”將值0返回給呼叫表示式。第二種形式“return (表示式)”計算表示式的值並將該值返回給呼叫表示式。在每個函式的末尾有一個隱含的“return (0)”。這允許一個函式終止並返回0,而不需要顯式返回語句。

函式還會改變變數ibase的用法。函式體中的所有常量都將在函式呼叫時使用ibase的值進行轉換。在函式執行過程中,ibase的更改將被忽略,但標準函式讀取除外,後者將始終使用ibase的當前值來轉換數字。

     當前版本的bc,在函式中添加了幾個擴充套件。首先,定義的格式稍微放鬆了一些。標準要求開始大括號與定義關鍵字在同一行,所有其他部分必須在下面的行上。這個版本的bc將允許之前的任何數目的換行符。在函式的開頭支撐之後,例如,下面的定義是合法的:

    define  d  (n)  { return  (2*n); }

    define  d  (n)

            { return  (2*n); }

     5)void型別

  函式可以定義為void。空函式不返回值,因此可能不會在任何需要值的地方使用。空函式在輸入行呼叫時不會產生任何輸出。關鍵字void放在關鍵字定義和函式名稱之間。例如,請考慮下面的例子

    define  py (y)  { print "--->", y, "<---", "0; }

    define  void  px (x)  { print "--->", x, "<---", "0; }

    py(1)

    --->1<---

    0                   //由於py不是void,因此有預設返回值,因此這裡列印了它的返回值,

    px(1)

    --->1<---           //px是void型別,最後不會列印返回值

此外,還為陣列添加了按變數呼叫。為了申明一個數組變數,函式中的陣列引數是這樣定義的“*name[]” 。

 

7、數學庫

     1)如果使用“-l”選項呼叫bc,則預載入一個數學庫,並將預設精度設定為20。數學庫中有一下的函式:

  s(x),計算x的正弦值,x是弧度值。

  c(x),計算x的餘弦值,x是弧度值。

  a(x),計算x的反正切值,返回弧度。

  l(x),計算x的自然對數。

  e(x),e的x次方。

  j(n,x),從n到x的階數。

     2)例子

  下面的句子可以將“pi”的值賦值給shell變數pi

pi = $(echo  "scale=10; 4*a(1)"  |  bc  -l)

  下面的句子就是數學庫中e的次方定義方式

scale = 20

/* Uses the fact that e^x = (e^(x/2))^2

    When x is small enough, we use the series:

    e^x = 1 + x + x^2/2! + x^3/3! + ...

*/

define e(x) {

    auto  a, d, e, f, i, m, v, z

 

    /* Check the sign of x. */

    if (x<0) {

        m = 1

        x = -x

    }

 

    /* Precondition x. */

    z = scale;

    scale = 4 + z + .44*x;

    while (x > 1) {

        f += 1;

        x /= 2;

    }

 

    /* Initialize the variables. */

    v = 1+x

    a = x

    d = 1

    for (i=2; 1; i++) {

        e = (a *= x) / (d *= i)

        if (e == 0) {

            if (f>0) while (f--)  v = v*v;

            scale = z

            if (m) return (1/v);

        return (v/1);

        }

        v += e

    }

}

     下面的語句實現一個計算支票簿餘額的簡單程式

scale=2

print "\nCheck book program!\n"

print "  Remember, deposits are negative transactions.\n"

print "  Exit by a 0 transaction.\n\n"

 

print "Initial balance? "; bal = read()

bal /= 1

print "\n"

while (1) {

    "current balance = "; bal

    "transaction? "; trans = read()

    if (trans == 0) break;

    bal -= trans

    bal /= 1

}

quit

     下面的語句採用遞迴的方式計算x的階乘

define f (x) {

    if (x <= 1) return (1);

    return (f(x-1) * x);

}

 

8、readline和libedit選項

     可以編譯GNU bc(通過一個配置選項)來使用GNU readline輸入編輯器庫或bsd libedit庫。這允許使用者在將行傳送到bc之前進行編輯。它還允許儲存以前鍵入的行的歷史記錄。當選擇此選項時,bc還有一個特殊變數。變數“history”是保留的歷史記錄行數。對於readline,值-1表示不限制歷史記錄的行數,0將禁用歷史記錄功能,預設值為100。

 

9、差別

  這個版本的bc是從POSIX P 1003.2/D11草案中實現的,包含了與草案和傳統實現相比的一些區別和擴充套件,它不是以傳統的方式使bc(1)實現的,這個版本是一個解析和執行程式位元組程式碼轉換的單一程序。這裡有一個“無文件”選項(-c),它導致程式將位元組碼輸出到標準輸出,而不是執行它。它主要用於除錯解析器和準備數學庫。差異的一個主要來源是擴充套件,下面列出一些差異和擴充套件:

     1)LANG環境變數,此版本在處理lang環境變數和從lc_開始的所有環境變數時不符合POSIX標準。

     2)名字,傳統和POSIX bc都有用於函式、變數和陣列的單字母名稱。它們被擴充套件為以字母開頭的多字元名稱,可以包含字母、數字和下劃線字元。

     3)字串,字串不允許包含NUL字元。POSIX表示所有字元都必須包含在字串中。

     4)last,POSIX bc中沒有last變數。

     5)比較,POSIX bc只允許在if語句、while語句和for語句的第二個表示式中進行比較。

     6)if語句,POSIX bc中if語句沒有else。

     7)for語句,POIX bc中要求for語句中的3個表示式都必須具備。

     8)&&,||,!,POSIX bc中沒有邏輯運算。

     9)read,POSIX bc沒有read功能。

     10)列印語句,POSIX bc沒有列印語句。

     11)continue語句,POSIX bc沒有continue語句。

     12)return,POSIX bc要求return的表示式加括號。

     13)陣列引數,POSIX bc不(目前)完全支援陣列引數。POSIX語法允許函式定義中的陣列,但沒有提供將陣列指定為實際引數的方法。(這很可能是語法上的疏忽。)傳統的bc實現只通過值陣列引數進行呼叫。

     14)函式,POSIX bc要求函式開頭的大括號和define關鍵字在同一行,語句在下一行。

     15)=+, =-, =*, =/, =%, =^。POSIX bc不要求定義這些“舊樣式”賦值操作符。此版本可能允許這些“舊樣式”賦值。使用限制語句檢視安裝的版本是否支援它們。如果它確實支援“舊樣式”賦值運算子,則“a=-1”語句將使a減少1,而不是將a設定為值-1。

     16)數字中的空格,bc的其他實現允許數字空格。例如,“x=1 3”將值13賦值給變數x。相同的語句將導致bc版本中的語法錯誤。

     17)錯誤和執行,在程式中發現語法和其他錯誤時,此實現與其他實現的程式碼不同。如果在函式定義中發現語法錯誤,則錯誤恢復機制將嘗試查詢語句的開頭並繼續解析函式。一旦在函式中發現語法錯誤,該函式將不可呼叫並變為未定義。互動執行程式碼中的語法錯誤將使當前執行塊失效。執行塊由在完整語句序列之後出現的行尾終止。例如

     a = 1

     b = 2

這個語句有兩個執行塊,而下面的語句

     {a = 1

     b = 2}

只有一個執行塊。任何執行時錯誤都會終止當前的執行塊,而警告則不會。

     18)中斷,在互動會話期間,SIGINT訊號(通常由終端上的“ctrl+c“生成)將導致當前執行塊的執行中斷。它將顯示一個“執行時”錯誤,指示哪個功能被中斷。在所有執行時結構被清除後,將列印一條訊息通知使用者bc準備好接收更多的輸入。所有先前定義的函式都保留定義,所有非自動變數的值是中斷點的值。在清理過程中,所有自動變數和函式引數都會被移除。對於一個非互動式會話,SIGINT訊號將終止bc的整個執行。

 

10、限制

     下面列出當前bc程式的一些限制,有一些限制可能已經被使用者修改過。

  1)BC_BASE_MAX,最大輸出基設定為999。最大輸入基為16。

  2)BC_DIM_MAX,這是當前分佈的65535以內的任意限制,每個機器可能都不一樣。

  3)BC_SCALE_MAX,小數點前後的位數都由INT_MAX限制。

  4)BC_STRING_MAX,字串中的字元字數由INT_MAX限制。

  5)exponent,指數運算中的指數值由LONG_MAX限制。

  6)variable names,當前對每個簡單變數、陣列和函式名字的限制32767。

 

11、環境變數

     下面的環境變數由bc程式來控制

  1)POSIXLY_CORRECT,和“-s”選項一樣。

  2)BC_ENV_ARGS,這是另一種獲取bc引數的機制。格式與命令列引數相同。這些引數是先處理的,因此環境引數中列出的任何檔案在任何命令列引數檔案之前都會被處理。這允許使用者設定“標準”選項和檔案,以便在每次呼叫環境變數中的檔案通常包含使用者希望在每次執行bc時定義的函式定義。

  3)BC_LINE_LENGTH,這應該是一個整數,指定數字輸出行中的字元數。這包括用於長數字的反斜槓和換行符。,如果值是0,將禁用多行功能。此變數的任何其他值如果小於3,則將行長設定為70。

 

12、例項

     1)簡單計算

[[email protected] ~]# bc

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'. 

12+23    //輸入加法表示式,回車

35       //得到結果

100/25   //輸入除法表示式,回車

4         //得到結果

quit     //退出指令

[[email protected] ~]# 

     2)執行for迴圈語句

for(i=0; i<3; i++){print "hello\n"}   //這是一個列印語句

hello

hello

hello