2006年6月1日

          利用回調簡化JDBC編程

          簡單看了一下spring 的jdbc支持,現在又要直接用到jdbc,想想就是痛苦。于是參考了spring,自己寫了一些簡單的java封裝類來簡化編程。


          廢話少說,我這里就用代碼來代言吧,看看怎樣簡化我們的JDBC編程,可以和以前進行對比。


          (1) JdbcTemplate。

          import java.sql.Connection;
          import java.sql.PreparedStatement;
          import java.sql.ResultSet;
          import java.sql.SQLException;
          import java.sql.Statement;


          import javax.sql.DataSource;


          import org.winter.util.DBUtil;


          /**
          ?* a simple JDBC template 模仿spring的JdbcTemplate
          ?*
          ?* @author bluestone
          ?* @version 1.0 2006-8-8
          ?*
          ?*/
          public class JdbcTemplate {


          ?private DataSource dataSource = null;


          ?public JdbcTemplate(DataSource ds) {
          ??this.dataSource = ds;
          ?}


          /**
          ? * 執行更新操作
          ? *
          ? * @param sql
          ? * @param setter
          ? * @return
          ? * @throws SQLException
          ? */
          ?public int update(String sql, PreparedStatementSetter setter)
          ???throws SQLException {
          ??Connection conn = null;
          ??reparedStatement ps = null;
          ??try {
          ???conn = dataSource.getConnection();
          ???ps = conn.prepareStatement(sql);
          ???setter.setValues(ps);
          ???return ps.executeUpdate();
          ??} finally {
          ???DBUtil.colseConnection(conn, ps, null);
          ??}
          ?}


          ?/**
          ? *
          ? * @param sql
          ? * @return
          ? * @throws SQLException
          ? */
          ?public boolean execute(String sql) throws SQLException {
          ??Connection conn = null;
          ??Statement stmt = null;
          ??try {
          ???conn = dataSource.getConnection();
          ???stmt = conn.createStatement();
          ???return stmt.execute(sql);
          ??} finally {
          ???DBUtil.colseConnection(conn, stmt, null);
          ??}
          ?}


          ?/**
          ? *
          ? * @param sql
          ? * @param setter
          ? * @param extractor
          ? * @return
          ? * @throws SQLException
          ? */
          ?public Object query(String sql, PreparedStatementSetter setter,
          ???ResultSetExtractor extractor) throws SQLException {
          ??Connection conn = null;
          ??reparedStatement ps = null;
          ??ResultSet rs = null;
          ??try {
          ???conn = dataSource.getConnection();
          ???ps = conn.prepareStatement(sql);
          ???setter.setValues(ps);
          ???rs = ps.executeQuery();
          ???return extractor.extractData(rs);
          ??} finally {
          ???DBUtil.colseConnection(conn, ps, rs);
          ??}
          ?}


          ?// .........................
          }


          (2)? PreparedStatementSetter


          public interface PreparedStatementSetter {
          ?void setValues(PreparedStatement ps) throws SQLException;
          }


          (3)? ResultSetExtractor


          public interface ResultSetExtractor {
          ?Object extractData(ResultSet rs) throws SQLException;
          }



          (4) 可以參考spring自己定義其他接口。。。


          用了這些輔助類,我們就可以像用spring那樣編程了(當然這只能用在對事務要求不高的應用環境中)。看看怎么使用:



          ?private JdbcTemplate template;


          ?public JobManageDao() throws BusinessException {
          ??try {
          ???template = new JdbcTemplate(DBHelper.getDataSource());
          ??} catch (NamingException e) {
          ???throw new BusinessException(e);
          ??}
          ?}


          public long saveJobInfo(final JobInfo info) throws BusinessException {
          ??final long id = IdGenerator.getIdLong();
          ??try {
          ???int j = template.update(INSERT_JOB_SQL, new PreparedStatementSetter() {


          ??public void setValues(PreparedStatement ps) throws SQLException {
          ?????int i = 1;
          ?????ps.setLong(i++, id);


          ?? //......


          ???}
          ???});
          ????? return j > 0 ? id : 0L;
          ??} catch (SQLException e) {
          ???? ?throw new BusinessException(e);
          ??}
          ?}

          posted @ 2006-08-24 12:38 bluestone 閱讀(341) | 評論 (0)編輯 收藏
           
          web開發經常遇到這樣的情形:寫代碼的模式基本相同,特別是在寫jdbc代碼時,會經常要先寫sql,然后調用PreparedStatement的setXXX方法,而讀取數據時要調用ResultSet的getXXX方法。如果表中的字段很多,那可夠你受的了;等你耐心把這些寫完,可能在某個地方卻出錯了。

          ????????如果沒有用ORM工具,這些又不能省了不寫。于是我考慮用代碼來生成這些sql 和 setXXX及getXXX方法。

          ??????? 生成代碼有許多方法,比如可以用腳本語言(個人喜歡用perl),也可以用模板技術。發現java里面已經有很多模板技術可以直接使用了,比如velocity、freemaker等。我一開始是直接用perl來生成代碼的,方法比較原始,就是字符串拼湊在一起。 后來發現有許多的模板技術可以利用。現在打算用velocity來生成代碼。說不定可以直接生成DAO、Biz、Bean、XML等一大堆東西,呵呵。等有空要好好研究一下。

          posted @ 2006-08-24 12:37 bluestone 閱讀(272) | 評論 (1)編輯 收藏
           
          在jsp頁面,一個表單如果字段很多的話,要寫很多request.getParameter(name)之類的代碼,如果用web framework的話,則可以免去寫這些代碼的麻煩。但如果不用framework是否也可以達到參數自動填充的功能呢? 答案是肯定的。

          ??? 下面是我在就業網重構時用到的一個java類,其中就是對BeanUtils進行了簡單的封裝。

          ???import java.sql.Date;
          ???import java.util.Map;


          ?? import org.apache.commons.beanutils.BeanUtils;
          ?? import org.apache.commons.beanutils.ConvertUtils;
          ?? import org.apache.commons.beanutils.converters.SqlDateConverter;

          ?? public class NullSafeBeanUtils {
          ??

          ?? public final static String EMPTY_STRING = "";
          ?
          ?? public static boolean isNull(Object obj) {
          ?????? return obj == null;
          ?? }

          ?? public static String getProperty(Object bean, String property) {
          ????? ?if (bean == null) {
          ?????????? ?return EMPTY_STRING;
          ????? ?}
          ??? ?try {
          ???????? ?String str = BeanUtils.getProperty(bean, property);
          ???????? ?if (str == null) {
          ????????????? return EMPTY_STRING;
          ??????? ?}
          ??????? return str;
          ???? } catch (Exception e) {
          ??????? ?return EMPTY_STRING;
          ?? }
          ? }

          ??public static void populate(Object bean, Map props) {
          ??? ?if (bean == null) {
          ??????? return;
          ???? }
          ?? ?try {
          ???? SqlDateConverter con = new SqlDateConverter(new Date(System.currentTimeMillis()));
          ????? ConvertUtils.register(con, java.sql.Date.class);
          ????? BeanUtils.populate(bean, props);
          ?? } catch (Exception e) {
          ??? ?e.printStackTrace();
          ?? }
          ?}
          ?//?此處省略了一些其他代碼
          ?}


          ?


          ??? 在這里,poplulate方法就是我用來自動填充參數的。要實現自動填充,只需簡單調用此方法就行了。看一個例子:


          ??? JobExperience jobExp = new JobExperience();

          ??? NullSafeBeanUtils.populate(jobExp, request.getParameterMap());


          ?? 是不是簡單了許多?要注意的是表單的各輸入字段名要和bean的各屬性名對應才能自動填充。另外NullSafeBeanUtils 的getProperty方法也很有用,可以避免寫

          ?? if (bean != null) {

          ????? yyy = bean.getXXX()==null?"":bean.getXXX()

          ???}

          ?? 這樣的代碼,直接寫NullSafeBeanUtils.getProperty(bean, "XXX")就可以了。

          posted @ 2006-08-24 12:35 bluestone 閱讀(947) | 評論 (3)編輯 收藏
           

          UNIQ(1)????User Commands???????? UNIQ(1)

          ?

          NAME
          ?????? uniq - remove duplicate lines from a sorted file
          SYNOPSIS
          ?????? uniq [OPTION]... [INPUT [OUTPUT]]

          DESCRIPTION
          ?????? Discard all but one of successive identical lines from INPUT (or stan-
          ?????? dard input), writing to OUTPUT (or standard output).

          ?????? Mandatory arguments to long options are mandatory? for? short? options
          ?????? too.

          ?????? -c, --count
          ?????? prefix lines by the number of occurrences

          ?????? -d, --repeated
          ?????? only print duplicate lines

          ?????? -D, --all-repeated[=delimit-method] print all duplicate lines
          ?????? delimit-method={none(default),prepend,separate}? Delimiting? is
          ?????? done with blank lines.

          ?????? -f, --skip-fields=N
          ?????? avoid comparing the first N fields

          ?????? -i, --ignore-case
          ?????? ignore differences in case when comparing

          ?????? -s, --skip-chars=N
          ?????? avoid comparing the first N characters

          ?????? -u, --unique
          ?????? only print unique lines

          ?????? -w, --check-chars=N
          ?????? compare no more than N characters in lines

          ?????? --help display this help and exit

          ?????? --version
          ?????? output version information and exit

          ?????? A field is? a? run? of? whitespace,? then? non-whitespace? characters.
          ?????? Fields are skipped before chars.

          AUTHOR
          ?????? Written by Richard Stallman and David MacKenzie.

          REPORTING BUGS
          ?????? Report bugs to <bug-coreutils@gnu.org>.

          COPYRIGHT
          ?????? Copyright ? 2004 Free Software Foundation, Inc.
          ?????? This? is? free software; see the source for copying conditions.?There
          ?????? is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICU-
          ?????? LAR PURPOSE.

          SEE ALSO
          ?????? The full documentation for uniq is maintained as a Texinfo manual.? If
          ?????? the info and uniq programs are properly installed at? your? site,? the
          ?????? command

          ?????? info coreutils uniq

          ?????? should give you access to the complete manual.

          posted @ 2006-06-02 13:46 bluestone 閱讀(201) | 評論 (0)編輯 收藏
           
          作者:cicc 2005-02-03 15:53:59 來自:Linux先生

          ??? a w k是一種程序語言,對文檔資料的處理具有很強的功能。awk 名稱是由它三個最初設計者的姓氏的第一個字母而命名的: Alfred V. Aho、Peter J. We i n b e rg e r、Brian W. Kernighan。
          ???a w k最初在1 9 7 7年完成。1 9 8 5年發表了一個新版本的a w k,它的功能比舊版本增強了不少。a w k能夠用很短的程序對文檔里的資料做修改、比較、提取、打印等處理。如果使用C 或P a s c a l等語言編寫程序完成上述的任務會十分不方便而且很花費時間,所寫的程序也會很大。
          ???a w k不僅僅是一個編程語言,它還是L i n u x系統管理員和程序員的一個不可缺少的工具。a w k語言本身十分好學,易于掌握,并且特別的靈活。
          ???gawk 是G N U計劃下所做的a w k,gawk 最初在1 9 8 6年完成,之后不斷地被改進、更新。gawk 包含awk 的所有功能。

          6.1 gawk的主要功能

          ???gawk 的主要功能是針對文件的每一行( l i n e ),也就是每一條記錄,搜尋指定的格式。當某一行符合指定的格式時,gawk 就會在此行執行被指定的動作。gawk 依此方式自動處理輸入文件的每一行直到輸入文件檔案結束。
          ???g a w k經常用在如下的幾個方面:
          ???? 根據要求選擇文件的某幾行,幾列或部分字段以供顯示輸出。
          ???? 分析文檔中的某一個字出現的頻率、位置等。
          ???? 根據某一個文檔的信息準備格式化輸出。
          ???? 以一個功能十分強大的方式過濾輸出文檔。
          ???? 根據文檔中的數值進行計算。

          6.2 如何執行gawk程序

          ???基本上有兩種方法可以執行g a w k程序。
          ???如果gawk 程序很短,則可以將gawk 直接寫在命令行,如下所示:
          ??????gawk 'program' input-file1 input-file2 ...
          ???
          ?? 其中program 包括一些pattern 和a c t i o n。
          ???如果gawk 程序較長,較為方便的做法是將gawk 程序存在一個文件中,gawk 的格式如下所示:
          ???gawk -f program-file input-file1 input-file2 ...
          ???gawk 程序的文件不止一個時,執行gawk 的格式如下所示:
          ???
          ???gawk -f program-file1 -f program-file2 ... input-file1 input-file2 ...

          6.3 文件、記錄和字段

          ???一般情況下,g a w k可以處理文件中的數值數據,但也可以處理字符串信息。如果數據沒有存儲在文件中,可以通過管道命令和其他的重定向方法給g a w k提供輸入。當然, g a w k只能處理文本文件(A S C I I碼文件)。?電話號碼本就是一個g a w k可以處理的文件的簡單例子。電話號碼本由很多條目組成,每一個條目都有同樣的格式:姓、名、地址、電話號碼。每一個條目都是按字母順序排列。在g a w k中,每一個這樣的條目叫做一個記錄。它是一個完整的數據的集合。例如,電話號碼本中的Smith John這個條目,包括他的地址和電話號碼,就是一條記錄。
          ???記錄中的每一項叫做一個字段。在g a w k中,字段是最基本的單位。多個記錄的集合組成了一個文件。
          ???大多數情況下,字段之間由一個特殊的字符分開,像空格、TA B、分號等。這些字符叫做字段分隔符。請看下面這個/ e t c / p a s s w d文件:
          t p a r k e r ; t 3 6 s 6 2 h s h ; 5 0 1 ; 1 0 1 ; Tim Parker;/home/tparker;/bin/bash
          etreijs;2ys639dj3h;502;101;Ed Tr e i j s ; / h o m e / e t r e i j s ; / b i n / t c s h
          y c h o w ; 1 h 2 7 s j ; 5 0 3 ; 1 0 1 ; Yvonne Chow;/home/ychow;/bin/bash
          ???你可以看出/ e t c / p a s s w d文件使用分號作為字段分隔符。/ e t c / p a s s w d文件中的每一行都包括七個字段:用戶名;口令;用戶I D;工作組I D;注釋; h o m e目錄;啟始的外殼。如果你想要查找第六個字段,只需數過五個分號即可。
          ???但考慮到以下電話號碼本的例子,你就會發現一些問題:
          Smith John 13 Wilson St. 555-1283
          Smith John 2736 Artside Dr Apt 123 555-2736
          Smith John 125 Westmount Cr 555-1726
          ???雖然我們能夠分辨出每個記錄包括四個字段,但g a w k卻無能為力。電話號碼本使用空格作為分隔符,所以g a w k認為S m i t h是第一個字段, John 是第二個字段,1 3是第三個字段,依次類推。就g a w k而言,如果用空格作為字段分隔符的話,則第一個記錄有六個字段,而第二個記錄有八個字段。
          ???所以,我們必須找出一個更好的字段分隔符。例如,像下面一樣使用斜杠作為字段分隔符:
          Smith/John/13 Wilson St./555-1283
          Smith/John/2736 Artside Dr/Apt/123/555-2736
          Smith/John/125 Westmount Cr/555-1726
          ???如果你沒有指定其他的字符作為字段分隔符,那么g a w k將缺省地使用空格或TA B作為字段分隔符。

          6.4 模式和動作

          ???在g a w k語言中每一個命令都由兩部分組成:一個模式( p a t t e r n)和一個相應的動作(a c t i o n)。只要模式符合,g a w k就會執行相應的動作。其中模式部分用兩個斜杠括起來,而動作部分用一對花括號括起來。例如:
          / p a t t e r n 1 / { a c t i o n 1 }
          / p a t t e r n 2 / { a c t i o n 2 }
          / p a t t e r n 3 / { a c t i o n 3 }
          ???所有的g a w k程序都是由這樣的一對對的模式和動作組成的。其中模式或動作都能夠被省略,但是兩個不能同時被省略。如果模式被省略,則對于作為輸入的文件里面的每一行,動作都會被執行。如果動作被省略,則缺省的動作被執行,既顯示出所有符合模式的輸入行而不做任何的改動。
          ???下面是一個簡單的例子,因為gawk 程序很短,所以將gawk 程序直接寫在外殼命令行:
          gawk '/tparker/' /etc/passwd

          ????此程序在上面提到的/ e t c / p a s s w d文件中尋找符合t p a r k e r模式的記錄并顯示(此例中沒有動作,所以缺省的動作被執行)。
          ???讓我們再看一個例子:
          ???gawk '/UNIX/{print $2}' file2.data
          ???此命令將逐行查找f i l e 2 . d a t a文件中包含U N I X的記錄,并打印這些記錄的第二個字段。你也可以在一個命令中使用多個模式和動作對,例如:
          gawk '/scandal/{print $1} /rumor/{print $2}' gossip_file
          ???此命令搜索文件g o s s i p _ f i l e中包括s c a n d a l的記錄,并打印第一個字段。然后再從頭搜索g o s s i p _ f i l e中包括r u m o r的記錄,并打印第二個字段。

          6.5 比較運算和數值運算

          ???g a w k有很多比較運算符,下面列出重要的幾個:
          = = 相等
          ! = 不相等
          > 大于
          < 小于
          > = 大于等于
          < = 小于等于
          ???例如:??gawk '$4 > 100' testfile
          ???將會顯示文件testfile 中那些第四個字段大于1 0 0的記錄。
          ???下表列出了g a w k中基本的數值運算符。
          ???運算符說明示例
          ???+ 加法運算2+6
          ???- 減法運算6-3
          ???* 乘法運算2*5
          ???/ 除法運算8/4
          ???^ 乘方運算3^2 (=9)
          ???% 求余數9%4 (=1)
          ???例如:{print $3/2} 顯示第三個字段被2除的結果。
          ???在g a w k中,運算符的優先權和一般的數學運算的優先權一樣。例如:{print $1+$2*$3}
          ???顯示第二個字段和第三個字段相乘,然后和第一個字段相加的結果。
          ???你也可以用括號改變優先次序。例如:
          ???{print ($1+$2)*$3}
          ???顯示第一個字段和第二個字段相加,然后和第三個字段相乘的結果。

          6.6 內部函數

          g a w k中有各種的內部函數,現在介紹如下:?

          6.6.1 隨機數和數學函數

          sqrt(x) 求x 的平方根
          sin(x) 求x 的正弦函數
          cos(x) 求x 的余弦函數
          a t a n 2 ( x,y) 求x / y的余切函數
          log(x) 求x 的自然對數
          exp(x) 求x 的e 次方
          int(x) 求x 的整數部分
          rand() 求0 和1之間的隨機數
          srand(x) 將x 設置為r a n d ( )的種子數

          6.6.2 字符串的內部函數

          ? i n d e x ( i n,find) 在字符串in 中尋找字符串find 第一次出現的地方,返回值是字符串find 出現在字符串in 里面的位置。如果在字符串in 里面找不到字符串f i n d,則返回值為0。
          例如:
          print index("peanut"," a n " )
          顯示結果3。
          ? length(string) 求出string 有幾個字符。
          例如:
          l e n g t h ( " a b c d e " )
          顯示結果5。
          ? m a t c h ( s t r i n g,r e g e x p ) 在字符串string 中尋找符合regexp 的最長、最靠左邊的子字符串。返回值是regexp 在string 的開始位置,即i n d e x值。match 函數將會設置系統變量R S TA RT 等于i n d e x的值,系統變量RLENGTH 等于符合的字符個數。如果不符合,則會設置R S TA RT 為0、RLENGTH 為- 1。
          ? s p r i n t f ( f o r m a t,e x p r e s s i o n 1,. . . ) 和printf 類似,但是sprintf 并不顯示,而是返回字符串。例如:
          sprintf("pi = %.2f (approx.)",2 2 / 7 )
          返回的字符串為pi = 3.14 (approx.)
          ? s u b ( r e g e x p,r e p l a c e m e n t,t a rg e t ) 在字符串t a rget 中尋找符合regexp 的最長、最靠左的地方,以字串replacement 代替最左邊的r e g e x p。
          例如:
          str = "water,w a t e r,e v e r y w h e r e "
          s u b ( / a t /, " i t h ",s t r )
          結果字符串s t r會變成
          w i t h e r,w a t e r,e v e r y w h e r e
          ? g s u b ( r e g e x p,r e p l a c e m e n t,t a rget) 與前面的s u b類似。在字符串t a rget 中尋找符合r e g e x p的所有地方,以字符串replacement 代替所有的r e g e x p。例如:
          s t r = " w a t e r,w a t e r,e v e r y w h e r e "g s u b ( / a t /, " i t h ",s t r )
          結果字符串s t r會變成
          w i t h e r,w i t h e r,e v e r y w h e r e
          ? s u b s t r ( s t r i n g,s t a r t,length) 返回字符串string 的子字符串,這個子字符串的長度為l e n g t h,從第start 個位置開始。例如:
          s u b s t r ( " w a s h i n g t o n ",5,3 )返回值為i n g
          如果沒有length ,則返回的子字符串是從第start 個位置開始至結束。
          例如:
          s u b s t r ( " w a s h i n g t o n ",5 )
          返回值為i n g t o n。
          ? tolower(string) 將字符串s t r i n g的大寫字母改為小寫字母。
          例如:
          tolower("MiXeD cAsE 123")
          返回值為mixed case 123。
          ? toupper(string) 將字符串s t r i n g的小寫字母改為大寫字母。
          例如:
          toupper("MiXeD cAsE 123")
          返回值為MIXED CASE 123。

          6.6.3 輸入輸出的內部函數

          ? close(filename) 將輸入或輸出的文件filename 關閉。
          ? system(command) 此函數允許用戶執行操作系統的指令,執行完畢后將回到g a w k程序。例如:
          BEGIN {system("ls")}

          6.7 字符串和數字

          字符串就是一連串的字符,它可以被g a w k逐字地翻譯。字符串用雙引號括起來。數字不能用雙引號括起來,并且g a w k將它當作一個數值。例如:
          gawk '$1 != "Tim" {print}' testfile
          此命令將顯示第一個字段和Ti m不相同的所有記錄。如果命令中Ti m兩邊不用雙引號,g a w k將不能正確執行。再如:
          gawk '$1 == "50" {print}' testfile
          ???此命令將顯示所有第一個字段和5 0這個字符串相同的記錄。g a w k不管第一字段中的數值的大小,而只是逐字地比較。這時,字符串5 0和數值5 0并不相等。

          6.8 格式化輸出

          ???我們可以讓動作顯示一些比較復雜的結果。例如:
          gawk '$1 != "Tim" {print $1,$ 5,$ 6,$2}' testfile
          將顯示t e s t f i l e文件中所有第一個字段和Ti m不相同的記錄的第一、第五、第六和第二個字段。進一步,你可以在p r i n t動作中加入字符串,例如:
          gawk '$1 != "Tim" {print "The entry for ",$ 1,"is not Tim. ",$2}' testfile
          ???p r i n t動作的每一部分用逗號隔開。
          ???借用C語言的格式化輸出指令,可以讓g a w k的輸出形式更為多樣。這時,應該用p r i n t f而不是p r i n t。例如:
          {printf "%5s likes this language\n",$ 2 }
          p r i n t f中的%5s 部分告訴gawk 如何格式化輸出字符串,也就是輸出5個字符長。它的值由printf 的最后部分指出,在此是第二個字段。\ n是回車換行符。如果第二個字段中存儲的是人名,則輸出結果大致如下:
          Tim likes this language
          G e o ff likes this language
          Mike likes this language
          Joe likes this language
          ???gawk 語言支持的其他格式控制符號如下:
          ? c 如果是字符串,則顯示第一個字符;如果是整數,則將數字以ASCII 字符的形式顯示。
          例如:
          printf “% c”,6 5
          結果將顯示字母A。
          ? d 顯示十進制的整數。
          ? i 顯示十進制的整數。
          ? e 將浮點數以科學記數法的形式顯示。
          例如:
          print “$ 4 . 3 e”,1 9 5 0
          結果將顯示1 . 9 5 0 e + 0 3。
          ? f 將數字以浮點的形式顯示。
          ? g 將數字以科學記數法的形式或浮點的形式顯示。數字的絕對值如果大于等于0 . 0 0 0 1則
          以浮點的形式顯示,否則以科學記數法的形式顯示。
          ? o 顯示無符號的八進制整數。
          ? s 顯示一個字符串。
          ? x 顯示無符號的十六進制整數。1 0至1 5以a至f表示。
          ? X 顯示無符號的十六進制整數。1 0至1 5以A至F表示。
          ? % 它并不是真正的格式控制字符,% %將顯示%。
          當你使用這些格式控制字符時,你可以在控制字符前給出數字,以表示你將用的幾位或幾個字符。例如,6 d表示一個整數有6位。再請看下面的例子:
          {printf "%5s works for %5s and earns %2d an hour",$ 1,$ 2,$ 3 }
          將會產生類似如下的輸出:
          Joe works for Mike and earns 12 an hour
          當處理數據時,你可以指定數據的精確位數
          {printf "%5s earns $%.2f an hour",$ 3,$ 6 }
          其輸出將類似于:
          Joe earns $12.17 an hour

          你也可以使用一些換碼控制符格式化整行的輸出。之所以叫做換碼控制符,是因為g a w k對這些符號有特殊的解釋。下面列出常用的換碼控制符:

          \a 警告或響鈴字符。
          \b 后退一格。
          \f 換頁。
          \n 換行。
          \r 回車。
          \t Ta b。
          \v 垂直的t a b。

          6.9 改變字段分隔符

          ???在g a w k中,缺省的字段分隔符一般是空格符或TA B。但你可以在命令行使用- F選項改變字符分隔符,只需在- F后面跟著你想用的分隔符即可。
          gawk -F" ;"'/tparker/{print}' /etc/passwd
          ???在此例中,你將字符分隔符設置成分號。注意: - F必須是大寫的,而且必須在第一個引號之前。

          6.10 元字符

          g a w k語言在格式匹配時有其特殊的規則。例如, c a t能夠和記錄中任何位置有這三個字符的字段匹配。但有時你需要一些更為特殊的匹配。如果你想讓c a t只和c o n c a t e n a t e匹配,則需要在格式兩端加上空格:
          / cat / {print}
          再例如,你希望既和c a t又和C AT匹配,則可以使用或(|):
          / cat | CAT / {print}
          在g a w k中,有幾個字符有特殊意義。下面列出可以用在g a w k格式中的這些字符:
          ? ^ 表示字段的開始。
          例如:$3 ~ /^b/
          ???如果第三個字段以字符b開始,則匹配。
          ? $ 表示字段的結束。
          例如:$3 ~ /b$/
          如果第三個字段以字符b結束,則匹配。
          ? . 表示和任何單字符m匹配。
          例如:$3 ~ /i.m/
          如果第三個字段有字符i,則匹配。
          ? | 表示“或”。
          例如:/ c a t | C AT/
          和cat 或C AT字符匹配。
          ? * 表示字符的零到多次重復。
          例如:/UNI*X/
          和U N X、U N I X、U N I I X、U N I I I X等匹配。
          ? + 表示字符的一次到多次重復。
          例如:
          /UNI+X/
          和U N I X、U N I I X等匹配。
          ? \{a,b\} 表示字符a次到b次之間的重復。
          例如:
          / U N I \ { 1,3 \ } X
          和U N I X、U N I I X和U N I I I X匹配。
          ? ? 表示字符零次和一次的重復。
          例如:
          /UNI?X/
          和UNX 和U N I X匹配。
          ? [] 表示字符的范圍。
          例如:
          /I[BDG]M/
          和I B M、I D M和I G M匹配
          ? [^] 表示不在[ ]中的字符。
          例如:
          /I[^DE]M/
          和所有的以I開始、M結束的包括三個字符的字符串匹配,除了I D M和I E M之外。

          6.11 調用gawk程序

          當需要很多對模式和動作時,你可以編寫一個g a w k程序(也叫做g a w k腳本)。在g a w k程序中,你可以省略模式和動作兩邊的引號,因為在g a w k程序中,模式和動作從哪開始和從哪結束時是很顯然的。你可以使用如下命令調用g a w k程序:
          gawk -f script filename
          此命令使g a w k對文件f i l e n a m e執行名為s c r i p t的g a w k程序。
          如果你不希望使用缺省的字段分隔符,你可以在f選項后面跟著F選項指定新的字段分隔符(當然你也可以在g a w k程序中指定),例如,使用分號作為字段分隔符:
          gawk -f script -F";" filename
          如果希望gawk 程序處理多個文件,則把各個文件名羅列其后:
          gawk -f script filename1 filename2 filename3 ...
          缺省情況下, g a w k的輸出將送往屏幕。但你可以使用L i n u x的重定向命令使g a w k的輸出送往一個文件:
          gawk -f script filename > save_file

          6.12 BEGIN和END

          ???有兩個特殊的模式在g a w k中非常有用。B E G I N模式用來指明g a w k開始處理一個文件之前執行一些動作。B E G I N經常用來初始化數值,設置參數等。E N D模式用來在文件處理完成后執行一些指令,一般用作總結或注釋。
          BEGIN 和E N D中所有要執行的指令都應該用花括號括起來。BEGIN 和E N D必須使用大寫。
          請看下面的例子:
          BEGIN { print "Starting the process the file" }
          $1 == "UNIX" {print}
          $2 > 10 {printf "This line has a value of %d",$ 2 }
          END { print "Finished processing the file. Bye!"}
          此程序中,先顯示一條信息: Starting the process the file,然后將所有第一個字段等于U N I X的整條記錄顯示出來,然后再顯示第二個字段大于10 的記錄,最后顯示信息: F i n i s h e dprocessing the file. Bye!。

          6.13 變量

          在g a w k中,可以用等號( = )給一個變量賦值:
          var1 = 10
          在g a w k中,你不必事先聲明變量類型。
          請看下面的例子:
          $1 == "Plastic" { count = count + 1 }
          如果第一個字段是P l a s t i c,則c o u n t的值加1。在此之前,我們應當給c o u n t賦予過初值,一般是在B E G I N部分。
          下面是比較完整的例子:
          BEGIN { count = 0 }
          $5 == "UNIX" { count = count + 1 }
          END { printf "%d occurrences of UNIX were found",count }
          變量可以和字段和數值一起使用,所以,下面的表達式均為合法:
          count = count + $6
          count = $5 - 8
          count = $5 + var1
          變量也可以是格式的一部分,例如:
          $2 > max_value {print "Max value exceeded by ",$2 -max_value}
          $4 - var1 < min_value {print "Illegal value of ",$ 4 }

          6.14 內置變量

          g a w k語言中有幾個十分有用的內置變量,現在列于下面:

          NR 已經讀取過的記錄數。
          FNR 從當前文件中讀出的記錄數。
          F I L E N A M E 輸入文件的名字。
          FS 字段分隔符(缺省為空格)。
          RS 記錄分隔符(缺省為換行)。
          OFMT 數字的輸出格式(缺省為% g)。
          OFS 輸出字段分隔符。
          ORS 輸出記錄分隔符。
          NF 當前記錄中的字段數。

          如果你只處理一個文件,則NR 和FNR 的值是一樣的。但如果是多個文件, N R是對所有的文件來說的,而FNR 則只是針對當前文件而言。例如:
          NR <= 5 {print "Not enough fields in the record"}
          檢查記錄數是否小于5,如果小于5,則顯示出錯信息。
          F S十分有用,因為F S控制輸入文件的字段分隔符。例如,在B E G I N格式中,使用如下的
          命令:
          F S = " : "

          6.15 控制結構

          6.15.1 if 表達式

          if 表達式的語法如下:
          if (expression){
          c o m m a n d s
          }
          e l s e {
          c o m m a n d s
          }
          例如:
          # a simple if loop
          (if ($1 == 0){
          print "This cell has a value of zero"
          }
          else {
          printf "The value is %d\n",$ 1
          } )
          再看下一個例子:
          # a nicely formatted if loop
          (if ($1 > $2){
          print "The first column is larger"
          } else {
          print "The second column is larger"
          } )

          6.15.2 while 循環
          while 循環的語法如下:
          while (expression){
          c o m m a n d s
          }
          例如:
          # interest calculation computes compound interest
          # inputs from a file are the amount,interest_rateand years
          {var = 1
          while (var <= $3) {
          p r i n t f ( " % f \ n ",$ 1 * ( 1 + $ 2 ) ^ v a r )
          v a r + +}
          }

          6.15.3 for 循環

          for 循環的語法如下:
          for (initialization; expression; increment) {
          c o m m a n d
          }
          例如:
          # interest calculation computes compound interest
          # inputs from a file are the amount,interest_rateand years
          {for (var=1; var <= $3; var++) {
          p r i n t f ( " % f \ n ",$ 1 * ( 1 + $ 2 ) ^ v a r )
          }
          }
          6.15.4 next 和exit

          next 指令用來告訴gawk 處理文件中的下一個記錄, 而不管現在正在做什么。語法如下:
          { command1
          c o m m a n d 2
          c o m m a n d 3
          n e x t
          c o m m a n d 4
          }
          ???程序只要執行到n e x t指令,就跳到下一個記錄從頭執行命令。因此,本例中, c o m m a n d 4指令永遠不會被執行。
          ???程序遇到e x i t指令后,就轉到程序的末尾去執行E N D,如果有E N D的話。

          6.16 數組

          g a w k語言支持數組結構。數組不必事先初始化。聲明一個數組的方法如下:
          a r r a y n a m e [ n u m ] = v a l u e
          請看下面的例子:
          # reverse lines in a file
          {line[NR] = $0 } # remember each line
          END {var=NR # output lines in reverse order
          while (var > 0){
          print line[var]
          v a r - -
          }
          }
          此段程序讀取一個文件的每一行,并用相反的順序顯示出來。我們使用N R作為數組的下標來存儲文件的每一條記錄,然后在從最后一條記錄開始,將文件逐條地顯示出來。

          6.17 用戶自定義函數

          復雜的gawk 程序常常可以使用自己定義的函數來簡化。調用用戶自定義函數與調用內部函數的方法一樣。函數的定義可以放在gawk 程序的任何地方。
          用戶自定義函數的格式如下:
          function name (parameter-list) {
          b o d y - o f - f u n c t i o n
          }
          name 是所定義的函數的名稱。一個正確的函數名稱可包括一序列的字母、數字、下標線( u n d e r s c o r e s ),但是不可用數字做開頭。p a r a m e t e r-list 是函數的全部參數的列表,各個參數之間以逗點隔開。body-of-function 包含gawk 的表達式,它是函數定義里最重要的部分,它決定函數實際要做的事情。
          下面這個例子,會將每個記錄的第一個字段的值的平方與第二個字段的值的平方加起來。
          {print "sum =",S q u a r e S u m ( $ 1,$ 2 ) }
          function SquareSum(x,y) {
          s u m = x * x + y * y
          return sum
          }
          ???到此,我們已經知道了g a w k的基本用法。g a w k語言十分易學好用,例如,你可以用g a w k編寫一段小程序來計算一個目錄中所有文件的個數和容量。如果用其他的語言,如C語言,則會十分的麻煩,相反,g a w k只需要幾行就可以完成此工作。

          6.18 幾個實例

          最后,再舉幾個g a w k的例子:
          gawk '{if (NF > max) max = NF}
          END {print max}'
          此程序會顯示所有輸入行之中字段的最大個數。
          gawk 'length($0) > 80'
          此程序會顯示出超過80 個字符的每一行。此處只有模式被列出,動作是采用缺省值顯示整個記錄。
          gawk 'NF > 0'
          顯示擁有至少一個字段的所有行。這是一個簡單的方法,將一個文件里的所有空白行刪除。
          gawk 'BEGIN {for (i = 1; i <= 7; i++)
          print int(101 * rand())}'
          此程序會顯示出范圍是0 到100 之間的7 個隨機數。
          ls -l files | gawk '{x += $4}; END {print "total bytes: " x}'
          此程序會顯示出所有指定的文件的總字節數。
          expand file | gawk '{if (x < length()) x = length()}
          END {print "maximum line length is " x}'
          此程序會將指定文件里最長一行的長度顯示出來。expand 會將tab 改成s p a c e,所以是用實際的右邊界來做長度的比較。
          gawk 'BEGIN {FS = ":"}
          {print $1 | "sort"}' /etc/passwd
          此程序會將所有用戶的登錄名稱,依照字母的順序顯示出來。
          gawk '{nlines++}
          END {print nlines}'
          此程序會將一個文件的總行數顯示出來。
          gawk 'END {print NR}'
          此程序也會將一個文件的總行數顯示出來,但是計算行數的工作由g a w k來做。
          gawk '{print NR,$ 0 } '
          此程序顯示出文件的內容時,會在每行的最前面顯示出行號,它的函數與‘ cat -n’類似。

          posted @ 2006-06-01 14:11 bluestone 閱讀(475) | 評論 (0)編輯 收藏
           
          主站蜘蛛池模板: 岳阳县| 兰州市| 彰化市| 高淳县| 顺平县| 彩票| 建阳市| 合作市| 板桥市| 高淳县| 嘉鱼县| 壤塘县| 宁陕县| 巍山| 奇台县| 达日县| 萨嘎县| 黔江区| 金川县| 郑州市| 德化县| 唐山市| 榆林市| 利川市| 凉城县| 石阡县| 松江区| 永靖县| 新泰市| 台南市| 汝阳县| 平凉市| 连云港市| 思茅市| 东山县| 建始县| 旺苍县| 平谷区| 阿城市| 文成县| 光山县|