• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Prayer

            在一般中尋求卓越
            posts - 1256, comments - 190, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理
            Awk 是一種優(yōu)秀的文本樣式掃描和處理工具。本文側(cè)重介紹了 awk 在數(shù)值計(jì)算方面的運(yùn)用,并通過幾個(gè)實(shí)際工作中的例子,闡述了如何利用 awk 的計(jì)算功能來提高我們的工作效率。

            Awk 是一種優(yōu)秀的文本樣式掃描和處理工具。 Awk 與 sed 和 grep 有些相似, 但功能比后者強(qiáng)不少。 awk 提供的功能包括樣式載入, 流控制,數(shù)學(xué)運(yùn)算符,進(jìn)程控制以及許多內(nèi)置的變量和函數(shù)等。 借助于這些功能, 我們可以很方便地利用 awk 對(duì)各種文件 (如試驗(yàn)產(chǎn)生的數(shù)據(jù)文件,數(shù)據(jù)庫文件等) 進(jìn)行處理。 本文介紹了 awk 在數(shù)值計(jì)算方面的運(yùn)用, 并通過幾個(gè)實(shí)際的例子, 闡述了如何利用 awk 的計(jì)算功能來提高我們的工作效率。

            Awk 基本的運(yùn)算符,數(shù)學(xué)函數(shù)以及簡(jiǎn)單的運(yùn)算實(shí)例

            Awk 支持不少常見的運(yùn)算符, 如 + (加),- (減), * (乘), / (除), ^ 或 ** (乘方), % (取模) 等等。 此外, awk 也提供了一些常用的數(shù)學(xué)函數(shù), 比如 sin(x), cos(x), exp(x), log(x), sqrt(x), rand()。 使用這些運(yùn)算符和函數(shù)可以直接進(jìn)行一些簡(jiǎn)單的運(yùn)算:


            清單 1. 用 awk 做簡(jiǎn)單的數(shù)值計(jì)算
            
                        echo | awk '{print 19+7}' ==> 26
                        echo | awk '{print 19-7}' ==> 12
                        echo | awk '{print 19*7}' ==> 133
                        echo | awk '{print 19/7}' ==> 2.71429
                        echo | awk '{print 19**7}' ==> 893871739
                        echo | awk '{print 19%7}' ==> 5
                        echo | awk '{print atan2(19, 7)}' ==> 1.21781
                        

            上面的計(jì)算也可以用一個(gè)腳本文件 calc.awk 來完成:


            清單 2. 腳本文件 calc.awk
            
                        {
                        print $1 " + " $2 " = " $1 + $2
                        print $1 " - " $2 " = " $1 - $2
                        print $1 " x " $2 " = " $1 * $2
                        print $1 " / " $2 " = " $1 / $2
                        print $1 " ^ " $2 " = " $1 ** $2
                        print $1 " mod " $2 " = " $1 % $2
                        print " atan2( " $1 " , " $2 " ) " " = " atan2($1, $2)
                        }
                        

            執(zhí)行 awk -f calc.awk 19 7 可以得到和清單 1 中一樣的計(jì)算結(jié)果。 這里選項(xiàng) -f 允許 awk 調(diào)用并執(zhí)行程序文件 calc.awk; 最后的 197 是輸入, 分別對(duì)應(yīng)于文件中的 $1$2





            回頁首


            復(fù)雜一些的數(shù)值計(jì)算

            現(xiàn)在我們利用 awk 來完成一些稍微復(fù)雜的計(jì)算。 我們首先用 awk 來計(jì)算 Fibonacci 數(shù)列,相應(yīng)的 awk 程序 Fib.awk 見清單3:


            清單 3. 計(jì)算 Fibonacci 數(shù)列的程序文件
            function fibo(n) {
                        if(n<=1) return 1;
                        return (fibo(n-2) + fibo(n-1));
                        }
                        BEGIN {
                        n = (ARGV[1] < 1) ? 1 : ARGV[1];
                        printf("%d\n", fibo(n));
                        exit;
                        }
                        

            計(jì)算時(shí)使用命令 awk -f Fib.awk n。 這里的輸入 n 是整數(shù)。 另外只要把上面程序中的函數(shù)fibo(n) 稍微改一下, 就可以用來進(jìn)行階乘的運(yùn)算, 修改后的代碼如下:


            清單 4. 計(jì)算價(jià)乘的 awk 腳本
            function factorial(n) {
                        if(n<=1) return 1;
                        return (n*factorial(n-1));
                        }
                        BEGIN {
                        n = (ARGV[1] < 1) ? 1 : ARGV[1];
                        printf("%d\n", factorial(n));
                        exit;
                        }
                        

            我們?cè)賮砜匆粋€(gè)求平方根的例子。 盡管 awk 提供了計(jì)算平方根的函數(shù), 但我們也可以通過自己寫程序來實(shí)現(xiàn), 相應(yīng)的算法如清單 5 所示; 清單 6 則給出了一個(gè)具體的例子: 求數(shù)字 3.7 的平方根:

            清單 5. 求平方根的算法

            求平方根的算法
            清單 6. 計(jì)算平方根的例子
            BEGIN {
                        a = 3.7;
                        x = a;
                        while((x**2-a)**2 > 1e-12) {
                        x = (x + a/x)/2;
                        }
                        print x
                        }
                        





            回頁首


            實(shí)例1: 快速計(jì)算兩個(gè)文件之間的時(shí)間差

            如果僅僅從事單純的數(shù)值計(jì)算, 恐怕 awk 不是我們最好的選擇, 畢竟 awk 是為了方便文本處理而設(shè)計(jì)的。 不過如果數(shù)值計(jì)算和文本有密切關(guān)系的話, 比方說計(jì)算之前要先處理文本中的數(shù)據(jù) (如查找,提取數(shù)據(jù)), 這時(shí) awk 的優(yōu)勢(shì)就會(huì)充分顯示出來。 而這樣的情況在工作中往往是經(jīng)常碰到的。 我們來看一個(gè)實(shí)際的例子。 假定我們要比較某些運(yùn)行在 Linux 集群上的并行程序的效率, 一個(gè)可行的方法是估算這些程序運(yùn)行所需的時(shí)間。 這些程序運(yùn)行的時(shí)間通常比較長(zhǎng), 可以從 10 幾個(gè)小時(shí)到一個(gè)多星期。 注意到程序在運(yùn)行中會(huì)不斷地生成數(shù)據(jù)文件, 而 Linux 系統(tǒng)會(huì)紀(jì)錄下每個(gè)數(shù)據(jù)文件被創(chuàng)建 (如果以前不存在) 或修改(如果以前存在) 的時(shí)間, 這樣就可以通過計(jì)算兩個(gè)文件的時(shí)間差來估計(jì)并行程序的效率。 我們知道 Linux 提供的 stat 命令可以用來獲取某個(gè)文件的各種屬性, 比如對(duì)數(shù)據(jù)文件 simu_space_1.dat 使用命令 stat simu_space_1.dat 會(huì)有如下的輸出:


            清單 7. 命令 stat simu_space_1.dat 的輸出
            File:  "simu_space_1.dat"
                        Size: 237928    	Blocks: 480        IO Block: 4096   regular Datei
                        Device: 801h/2049d	Inode: 2768915     Links: 1
                        Access: (0644/-rw-r--r--)  Uid: ( 1000/     nst)   Gid: ( 1000/     nst)
                        Access: 2008-11-14 10:56:05.000000000 +0100
                        Modify: 2008-11-13 23:26:44.000000000 +0100
                        Change: 2008-11-13 23:26:44.000000000 +0100
                        

            以上輸出包含了關(guān)鍵字 ’Modify’ 的一行中紀(jì)錄下了文件被修改的時(shí)間。 所以原則上說只要對(duì)兩個(gè)文件分別使用 stat 命令, 得到它們的修改時(shí)間, 就可以計(jì)算出它們之間的時(shí)間差。 如果計(jì)算的次數(shù)很少的話, 這個(gè)工作當(dāng)然可以手工完成。 不過要頻繁計(jì)算的話就很費(fèi)時(shí)間了, 而且出錯(cuò)的幾率也會(huì)變大。 這種情況下我們可以求助 awk, 讓它來自動(dòng)完成這個(gè)計(jì)算工作, 為此我們創(chuàng)建了下面的腳本 time_df.awk:


            清單 8. 計(jì)算時(shí)間差的 awk 程序
            BEGIN {
                        n = 0;
                        d1 = 0;
                        s1 = 0;
                        FS = ":|-| *";
                        }
                        {
                        for(i=1; i<=NF; i++)
                        {
                        if($i~/Modify/)
                        {
                        n = n + 1;
                        d = $(i+4);
                        h = $(i+5);
                        m = $(i+6);
                        s = $(i+7);
                        d1 = d1 + ((-1)**n)*d*24*3600;
                        s1 = s1 + ((-1)**n)*(3600*h + 60*m + s);
                        }
                        }
                        }
                        END {
                        s1 = s1 + d1;
                        D = int(s1/(24*3600));
                        H = int((s1 - D*24*3600)/3600);
                        M = int((s1-D*24*3600-H*3600)/60);
                        S = s1 % 60;
                        printf("The total time required %d days, %d hours,   \
                        %d minutes and %d seconds\n", D, H, M, S) ;
                        }
                        

            上面的代碼是基于如下的考慮: 首先使用 awk 找到包含 ’Modify’ 關(guān)鍵字的那一行, 然后把其中有關(guān)日期和時(shí)間的數(shù)據(jù)提取出來。 由于直接對(duì)日期和時(shí)間做減法不是很方便, 所以先把日期和時(shí)間轉(zhuǎn)化為一個(gè)以秒為單位的數(shù)字 (從每個(gè)月的第一天0時(shí)0分0秒算起)。 容易理解, 由兩個(gè)數(shù)字相減得到的時(shí)間差也是以秒為單位的。 為了能直觀顯示, 輸出時(shí)再把這個(gè)時(shí)間差表達(dá)為天, 小時(shí), 分鐘和秒。 要計(jì)算兩個(gè)文件 simu_space_1.dat 和 simu_space_100.dat 之間的時(shí)間差,可以用下面的命令:


            清單 9. 計(jì)算文件時(shí)間差的命令
            stat simu_space_1.dat simu_space_100.dat | awk -f time_df.awk
                        

            先生成的文件 simu_space_1.dat (也就是時(shí)間較早一些的) 放在前面,后生成的文件simu_space_100.dat 放在后面。 如果要算另外兩個(gè)文件之間的時(shí)間差, 只要換一下文件名就可以了。 借助于上面的 awk 代碼我們可以快速且精確地得到任意兩個(gè)數(shù)據(jù)文件的時(shí)間間隔。 需要指出的是, 上面的程序沒有考慮跨月度這種情況。 也就是說, 如果第一個(gè)數(shù)據(jù)文件是在某個(gè)月的月末生成, 而第二個(gè)文件是在下個(gè)月的月初生成, 這時(shí)就不能用它來計(jì)算, 因?yàn)榈玫降臅r(shí)間是沒有意義的負(fù)數(shù)。





            回頁首


            實(shí)例2: 驗(yàn)證通量:從多個(gè)文件中提取數(shù)據(jù)并計(jì)算

            這個(gè)例子是通過計(jì)算不同位置處的流體的通量來驗(yàn)證它們是否相同。 這里的通量可視為某個(gè)截面上通過的顆粒濃度, 流體的速度和截面面積的乘積。 現(xiàn)在的問題是濃度, 速度等參數(shù)分布在不同的數(shù)據(jù)文件中, 而這些文件是字符和數(shù)據(jù)共存的, 比如包含濃度的文件 simu_space_1.dat 有如下的格式:

            清單 10. 數(shù)據(jù)文件 simu_space_1.dat 的格式

            {0.436737, 0.429223, 3.000000, 1.000000, 43300806482080792.000000, 243231808.137785},

            {1.296425, 0.429223, 3.000000, 1.000000, 107468809895964656.000000, 584622938.047805},

            {2.128973, 0.429223, 3.000000, 1.000000, 102324821165926400.000000, 539067822.351442},

            ......

            {19.358569, 4.875000, 3.000000, 1.000000, 257544788738191712.000000, 1460324590.999991},

            {19.620925, 4.875000, 3.000000, 1.000000, 266676357086157504.000000, 1464352706.940682},

            {19.875000, 4.875000, 3.000000, 1.000000, 260249342336872224.000000, 1383971975.659338},

            第一步當(dāng)然是從上面的文件中把某個(gè)位置上的濃度數(shù)據(jù) (每一行左起第五個(gè)數(shù)字) 提取出來。 下面的 awk 代碼是把位置 x = 0.429223 處的濃度提取出來, 并保存到一個(gè)臨時(shí)文件 number.txt 中:


            清單 11. 提取指定位置處的數(shù)據(jù)并保存
            awk  -F'{|,\t|},' '{for(i=1; i<NF; i++) {if($i~/0.429223/) print $(i+3)}}'  \
                        simu_space_1.dat > number.txt
                        

            現(xiàn)在文件 number.txt 中有了一列濃度數(shù)據(jù)。 接著我們從其他文件中提取在同一位置處的速度和面積的數(shù)據(jù), 然后把它們分別保存到臨時(shí)文件 velocity.txt 和 area.txt 中。 然后把三個(gè)臨時(shí)文件中的數(shù)據(jù)合并到另一個(gè)文件 flux.txt 中以方便 awk 的計(jì)算。 這個(gè)合并操作可以用工具 paste 來輕松完成, 代碼如清單 12:


            清單 12. 合并不同文件中的數(shù)據(jù)到一個(gè)文件
            paste number.txt velocity.txt area.txt > flux.txt
                        

            現(xiàn)在 flux.txt 中包含了三列數(shù)據(jù), 分別是濃度,速度和面積。 按照前面介紹的通量計(jì)算方法, 文件 flux.txt 中每一行的三個(gè)數(shù)據(jù)要首先相乘, 然后再把所有的乘積加起來就可以得到通過那個(gè)截面的通量了, 具體的代碼見清單13:


            清單 13. 計(jì)算通量的 awk 代碼
            awk '{x=x+($1*$2*$3)} END {print x}' flux.txt
                        

            上面的代碼使用了一個(gè)變量 x, 第一次執(zhí)行時(shí), x 被賦予文件 flux.txt 中第一行三個(gè)數(shù)據(jù)的乘積。 第二次執(zhí)行時(shí), 它保留了第一次計(jì)算的值并加上第二行三個(gè)數(shù)據(jù)的乘積, 以此類推, 直到達(dá)到累計(jì)的總合。 END 的作用是只顯示最后的結(jié)果, 而不顯示中間的累加結(jié)果。 我們可以做一個(gè)比較, 以前我們是利用其他的軟件 (比如 Excel 或者 OpenOffice Calc) 來計(jì)算通量的。 這必然要涉及到導(dǎo)入數(shù)據(jù), 選擇相應(yīng)的計(jì)算函數(shù)等一系列的操作, 而用 awk 只要一行代碼! 如果再考慮到計(jì)算之前從不同文件中提取數(shù)據(jù)的工作也是由 awk 完成的 (其實(shí)也就是幾行代碼), 所以對(duì)本例而言使用 awk 節(jié)約了可觀的時(shí)間。





            回頁首


            總結(jié)

            不應(yīng)忽視 awk 的數(shù)值計(jì)算功能, 它能完成從簡(jiǎn)單到比較復(fù)雜的數(shù)值運(yùn)算。 尤其當(dāng)計(jì)算過程中涉及到數(shù)據(jù)文件的處理, 這時(shí)使用 awk 往往會(huì)很方便。 因?yàn)?awk 本身有很強(qiáng)的文本處理功能, 它可以輕松地把數(shù)據(jù)從文本中分離出來, 然后再進(jìn)行相應(yīng)的計(jì)算。 本文的實(shí)例說明了如果能靈活地使用 awk 的這些功能, 有可能會(huì)顯著地提升我們的工作效率。



            參考資料



            關(guān)于作者

             

            在德國(guó) Duisburg-Essen 大學(xué), NST 工作. 對(duì) Linux 和 open source software 很感興趣.

            伊人久久亚洲综合影院| 色综合久久无码五十路人妻| 国产三级久久久精品麻豆三级 | 久久99精品久久久久久hb无码| 2022年国产精品久久久久| 国产精品无码久久四虎| 国产成人精品综合久久久| 99久久精品日本一区二区免费| 久久国产视屏| 久久精品99久久香蕉国产色戒 | 亚洲精品97久久中文字幕无码| 久久久久亚洲AV成人片| 合区精品久久久中文字幕一区| 日韩人妻无码一区二区三区久久| 国产一久久香蕉国产线看观看| 亚洲国产成人精品久久久国产成人一区二区三区综 | 午夜精品久久久久| 91精品婷婷国产综合久久 | 亚洲精品午夜国产va久久| 久久99国产精品99久久| 亚洲欧美成人综合久久久| 久久久久国色AV免费看图片| 狠狠色丁香婷婷久久综合不卡 | 精品久久人人爽天天玩人人妻| 久久综合香蕉国产蜜臀AV| 人妻无码精品久久亚瑟影视 | 精品久久久无码人妻中文字幕豆芽| 无码8090精品久久一区| 久久乐国产精品亚洲综合| 91久久香蕉国产熟女线看| 国产一区二区三区久久| 嫩草影院久久99| 国产精品免费久久久久电影网| 久久精品嫩草影院| 欧美日韩中文字幕久久伊人| 久久国产精品久久| 国内精品久久九九国产精品| 精品久久久久久久中文字幕| 久久国产精品无码网站| 中文精品99久久国产 | 国产精品伊人久久伊人电影|