2006年8月24日

          利用回調(diào)簡化JDBC編程

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


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


          (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;
          ?}


          /**
          ? * 執(zhí)行更新操作
          ? *
          ? * @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那樣編程了(當(dāng)然這只能用在對事務(wù)要求不高的應(yīng)用環(huán)境中)。看看怎么使用:



          ?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開發(fā)經(jīng)常遇到這樣的情形:寫代碼的模式基本相同,特別是在寫jdbc代碼時(shí),會(huì)經(jīng)常要先寫sql,然后調(diào)用PreparedStatement的setXXX方法,而讀取數(shù)據(jù)時(shí)要調(diào)用ResultSet的getXXX方法。如果表中的字段很多,那可夠你受的了;等你耐心把這些寫完,可能在某個(gè)地方卻出錯(cuò)了。

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

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

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

          ??? 下面是我在就業(yè)網(wǎng)重構(gòu)時(shí)用到的一個(gè)java類,其中就是對BeanUtils進(jìn)行了簡單的封裝。

          ???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方法就是我用來自動(dòng)填充參數(shù)的。要實(shí)現(xiàn)自動(dòng)填充,只需簡單調(diào)用此方法就行了。看一個(gè)例子:


          ??? JobExperience jobExp = new JobExperience();

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


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

          ?? if (bean != null) {

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

          ???}

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

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

          2006年6月2日

          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)編輯 收藏

          2006年6月1日

          作者:cicc 2005-02-03 15:53:59 來自:Linux先生

          ??? a w k是一種程序語言,對文檔資料的處理具有很強(qiáng)的功能。awk 名稱是由它三個(gè)最初設(shè)計(jì)者的姓氏的第一個(gè)字母而命名的: 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年發(fā)表了一個(gè)新版本的a w k,它的功能比舊版本增強(qiáng)了不少。a w k能夠用很短的程序?qū)ξ臋n里的資料做修改、比較、提取、打印等處理。如果使用C 或P a s c a l等語言編寫程序完成上述的任務(wù)會(huì)十分不方便而且很花費(fèi)時(shí)間,所寫的程序也會(huì)很大。
          ???a w k不僅僅是一個(gè)編程語言,它還是L i n u x系統(tǒng)管理員和程序員的一個(gè)不可缺少的工具。a w k語言本身十分好學(xué),易于掌握,并且特別的靈活。
          ???gawk 是G N U計(jì)劃下所做的a w k,gawk 最初在1 9 8 6年完成,之后不斷地被改進(jìn)、更新。gawk 包含awk 的所有功能。

          6.1 gawk的主要功能

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

          6.2 如何執(zhí)行g(shù)awk程序

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

          6.3 文件、記錄和字段

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

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

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

          6.5 比較運(yùn)算和數(shù)值運(yùn)算

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

          6.6 內(nèi)部函數(shù)

          g a w k中有各種的內(nèi)部函數(shù),現(xiàn)在介紹如下:?

          6.6.1 隨機(jī)數(shù)和數(shù)學(xué)函數(shù)

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

          6.6.2 字符串的內(nèi)部函數(shù)

          ? i n d e x ( i n,find) 在字符串in 中尋找字符串find 第一次出現(xiàn)的地方,返回值是字符串find 出現(xiàn)在字符串in 里面的位置。如果在字符串in 里面找不到字符串f i n d,則返回值為0。
          例如:
          print index("peanut"," a n " )
          顯示結(jié)果3。
          ? length(string) 求出string 有幾個(gè)字符。
          例如:
          l e n g t h ( " a b c d e " )
          顯示結(jié)果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 函數(shù)將會(huì)設(shè)置系統(tǒng)變量R S TA RT 等于i n d e x的值,系統(tǒng)變量RLENGTH 等于符合的字符個(gè)數(shù)。如果不符合,則會(huì)設(shè)置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 )
          結(jié)果字符串s t r會(huì)變成
          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 )
          結(jié)果字符串s t r會(huì)變成
          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 的子字符串,這個(gè)子字符串的長度為l e n g t h,從第start 個(gè)位置開始。例如:
          s u b s t r ( " w a s h i n g t o n ",5,3 )返回值為i n g
          如果沒有l(wèi)ength ,則返回的子字符串是從第start 個(gè)位置開始至結(jié)束。
          例如:
          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 輸入輸出的內(nèi)部函數(shù)

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

          6.7 字符串和數(shù)字

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

          6.8 格式化輸出

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

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

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

          6.9 改變字段分隔符

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

          6.10 元字符

          g a w k語言在格式匹配時(shí)有其特殊的規(guī)則。例如, c a t能夠和記錄中任何位置有這三個(gè)字符的字段匹配。但有時(shí)你需要一些更為特殊的匹配。如果你想讓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è)字符有特殊意義。下面列出可以用在g a w k格式中的這些字符:
          ? ^ 表示字段的開始。
          例如:$3 ~ /^b/
          ???如果第三個(gè)字段以字符b開始,則匹配。
          ? $ 表示字段的結(jié)束。
          例如:$3 ~ /b$/
          如果第三個(gè)字段以字符b結(jié)束,則匹配。
          ? . 表示和任何單字符m匹配。
          例如:$3 ~ /i.m/
          如果第三個(gè)字段有字符i,則匹配。
          ? | 表示“或”。
          例如:/ c a t | C AT/
          和cat 或C AT字符匹配。
          ? * 表示字符的零到多次重復(fù)。
          例如:/UNI*X/
          和U N X、U N I X、U N I I X、U N I I I X等匹配。
          ? + 表示字符的一次到多次重復(fù)。
          例如:
          /UNI+X/
          和U N I X、U N I I X等匹配。
          ? \{a,b\} 表示字符a次到b次之間的重復(fù)。
          例如:
          / U N I \ { 1,3 \ } X
          和U N I X、U N I I X和U N I I I X匹配。
          ? ? 表示字符零次和一次的重復(fù)。
          例如:
          /UNI?X/
          和UNX 和U N I X匹配。
          ? [] 表示字符的范圍。
          例如:
          /I[BDG]M/
          和I B M、I D M和I G M匹配
          ? [^] 表示不在[ ]中的字符。
          例如:
          /I[^DE]M/
          和所有的以I開始、M結(jié)束的包括三個(gè)字符的字符串匹配,除了I D M和I E M之外。

          6.11 調(diào)用gawk程序

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

          6.12 BEGIN和END

          ???有兩個(gè)特殊的模式在g a w k中非常有用。B E G I N模式用來指明g a w k開始處理一個(gè)文件之前執(zhí)行一些動(dòng)作。B E G I N經(jīng)常用來初始化數(shù)值,設(shè)置參數(shù)等。E N D模式用來在文件處理完成后執(zhí)行一些指令,一般用作總結(jié)或注釋。
          BEGIN 和E N D中所有要執(zhí)行的指令都應(yīng)該用花括號括起來。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,然后將所有第一個(gè)字段等于U N I X的整條記錄顯示出來,然后再顯示第二個(gè)字段大于10 的記錄,最后顯示信息: F i n i s h e dprocessing the file. Bye!。

          6.13 變量

          在g a w k中,可以用等號( = )給一個(gè)變量賦值:
          var1 = 10
          在g a w k中,你不必事先聲明變量類型。
          請看下面的例子:
          $1 == "Plastic" { count = count + 1 }
          如果第一個(gè)字段是P l a s t i c,則c o u n t的值加1。在此之前,我們應(yīng)當(dāng)給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 }
          變量可以和字段和數(shù)值一起使用,所以,下面的表達(dá)式均為合法:
          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 內(nèi)置變量

          g a w k語言中有幾個(gè)十分有用的內(nèi)置變量,現(xiàn)在列于下面:

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

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

          6.15 控制結(jié)構(gòu)

          6.15.1 if 表達(dá)式

          if 表達(dá)式的語法如下:
          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
          } )
          再看下一個(gè)例子:
          # 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 循環(huán)
          while 循環(huán)的語法如下:
          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 循環(huán)

          for 循環(huán)的語法如下:
          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 處理文件中的下一個(gè)記錄, 而不管現(xiàn)在正在做什么。語法如下:
          { 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
          }
          ???程序只要執(zhí)行到n e x t指令,就跳到下一個(gè)記錄從頭執(zhí)行命令。因此,本例中, c o m m a n d 4指令永遠(yuǎn)不會(huì)被執(zhí)行。
          ???程序遇到e x i t指令后,就轉(zhuǎn)到程序的末尾去執(zhí)行E N D,如果有E N D的話。

          6.16 數(shù)組

          g a w k語言支持?jǐn)?shù)組結(jié)構(gòu)。數(shù)組不必事先初始化。聲明一個(gè)數(shù)組的方法如下:
          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 - -
          }
          }
          此段程序讀取一個(gè)文件的每一行,并用相反的順序顯示出來。我們使用N R作為數(shù)組的下標(biāo)來存儲(chǔ)文件的每一條記錄,然后在從最后一條記錄開始,將文件逐條地顯示出來。

          6.17 用戶自定義函數(shù)

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

          6.18 幾個(gè)實(shí)例

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

          posted @ 2006-06-01 14:11 bluestone 閱讀(475) | 評論 (0)編輯 收藏
          僅列出標(biāo)題  
           
          主站蜘蛛池模板: 唐河县| 从化市| 房产| 北宁市| 吐鲁番市| 波密县| 新丰县| 宜君县| 鄱阳县| 仙桃市| 敦煌市| 阜康市| 清徐县| 龙游县| 桦南县| 磐安县| 泗洪县| 石家庄市| 海门市| 当涂县| 墨江| 贵定县| 吉水县| 新邵县| 宽甸| 乐业县| 定州市| 山阴县| 泸水县| 望城县| 益阳市| 宜川县| 昌宁县| 寻乌县| 平武县| 木兰县| 齐河县| 金华市| 四会市| 甘谷县| 武宣县|