TCP连接状态详解

TCP连接状态详解

    

        

            

        

    

            

            

            

tcp状态:

            
            

LISTEN:侦听来自远方的TCP端口的连接请求
            
            SYN-SENT:再发送连接请求后等待匹配的连接请求
            
            SYN-RECEIVED:再收到和发送一个连接请求后等待对方对连接请求的确认
            
            ESTABLISHED:代表一个打开的连接
            
            FIN-WAIT-1:等待远程TCP连接中断请求,或先前的连接中断请求的确认
            
            FIN-WAIT-2:从远程TCP等待连接中断请求
            
            CLOSE-WAIT:等待从本地用户发来的连接中断请求
            
            CLOSING:等待远程TCP对连接中断的确认
            
            LAST-ACK:等待原来的发向远程TCP的连接中断请求的确认
            
            TIME-WAIT:等待足够的时间以确保远程TCP接收到连接中断请求的确认
            
            CLOSED:没有任何连接状态

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

 

            

 

            

            

 

            

            

 

            

            

 

            

TCP是一个面向连接的协议,所以在连接双方发送数据之前,都需要首先建立一条连接。这和前面讲到的协议完全不同。前面讲的所有协议都只是发送数据而已,大多数都不关心发送的数据是不是送到,UDP尤其明显,从编程的角度来说,UDP编程也要简单的多—-UDP都不用考虑数据分片。

            

书中用telnet登陆退出来解释TCP协议连接的建立和中止的过程,可以看到,TCP连接的建立可以简单的称为三次握手,而连接的中止则可以叫做四次握手

            

1.连接的建立

            

在建立连接的时候,客户端首先向服务器申请打开某一个端口(用SYN段等于1的TCP报文),然后服务器端发回一个ACK报文通知客户端请求报文收到,客户端收到确认报文以后再次发出确认报文确认刚才服务器端发出的确认报文(绕口么),至此,连接的建立完成。这就叫做三次握手。如果打算让双方都做好准备的话,一定要发送三次报文,而且只需要三次报文就可以了。

            

可以想见,如果再加上TCP的超时重传机制,那么TCP就完全可以保证一个数据包被送到目的地。

            

2.结束连接

            

TCP有一个特别的概念叫做half-close,这个概念是说,TCP的连接是全双工(可以同时发送和接收)连接,因此在关闭连接的时候,必须关闭传和送两个方向上的连接。客户机给服务器一个FIN为1的TCP报文,然后服务器返回给客户端一个确认ACK报文,并且发送一个FIN报文,当客户机回复ACK报文后(四次握手),连接就结束了。

            

3.最大报文长度

            

在建立连接的时候,通信的双方要互相确认对方的最大报文长度(MSS),以便通信。一般这个SYN长度是MTU减去固定IP首部和TCP首部长度。对于一个以太网,一般可以达到1460字节。当然如果对于非本地的IP,这个MSS可能就只有536字节,而且,如果中间的传输网络的MSS更佳的小的话,这个值还会变得更小。

            

4.TCP的状态迁移图

            

书P182页给出了TCP的状态图,这是一个看起来比较复杂的状态迁移图,因为它包含了两个部分—服务器的状态迁移和客户端的状态迁移,如果从某一个角度出发来看这个图,就会清晰许多,这里面的服务器和客户端都不是绝对的,发送数据的就是客户端,接受数据的就是服务器。

            

4.1.客户端应用程序的状态迁移图

            

客户端的状态可以用如下的流程来表示:

            

CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED

            

以上流程是在程序正常的情况下应该有的流程,从书中的图中可以看到,在建立连接时,当客户端收到SYN报文的ACK以后,客户端就打开了数据交互地连接。而结束连接则通常是客户端主动结束的,客户端结束应用程序以后,需要经历FIN_WAIT_1,FIN_WAIT_2等状态,这些状态的迁移就是前面提到的结束连接的四次握手。

            

4.2.服务器的状态迁移图

            

服务器的状态可以用如下的流程来表示:

            

CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED

            

在建立连接的时候,服务器端是在第三次握手之后才进入数据交互状态,而关闭连接则是在关闭连接的第二次握手以后(注意不是第四次)。而关闭以后还要等待客户端给出最后的ACK包才能进入初始的状态。

            

4.3.其他状态迁移

            

书中的图还有一些其他的状态迁移,这些状态迁移针对服务器和客户端两方面的总结如下

            

 

            

                    

  1. LISTEN->SYN_SENT,对于这个解释就很简单了,服务器有时候也要打开连接的嘛。
  2.                 

  3. SYN_SENT->SYN收到,服务器和客户端在SYN_SENT状态下如果收到SYN数据报,则都需要发送SYN的ACK数据报并把自己的状态调整到SYN收到状态,准备进入ESTABLISHED
  4.                 

  5. SYN_SENT->CLOSED,在发送超时的情况下,会返回到CLOSED状态。
  6.                 

  7. SYN_收到->LISTEN,如果受到RST包,会返回到LISTEN状态。
  8.                 

  9. SYN_收到->FIN_WAIT_1,这个迁移是说,可以不用到ESTABLISHED状态,而可以直接跳转到FIN_WAIT_1状态并等待关闭。
  10.             

            

4.4.2MSL等待状态

            

书中给的图里面,有一个TIME_WAIT等待状态,这个状态又叫做2MSL状态,说的是在TIME_WAIT2发送了最后一个ACK数据报以后,要进入TIME_WAIT状态,这个状态是防止最后一次握手的数据报没有传送到对方那里而准备的(注意这不是四次握手,这是第四次握手的保险状态)。这个状态在很大程度上保证了双方都可以正常结束,但是,问题也来了。

            

由于插口的2MSL状态(插口是IP和端口对的意思,socket),使得应用程序在2MSL时间内是无法再次使用同一个插口的,对于客户程序还好一些,但是对于服务程序,例如httpd,它总是要使用同一个端口来进行服务,而在2MSL时间内,启动httpd就会出现错误(插口被使用)。为了避免这个错误,服务器给出了一个平静时间的概念,这是说在2MSL时间内,虽然可以重新启动服务器,但是这个服务器还是要平静的等待2MSL时间的过去才能进行下一次连接。

            

4.5.FIN_WAIT_2状态

            

这就是著名的半关闭的状态了,这是在关闭连接时,客户端和服务器两次握手之后的状态。在这个状态下,应用程序还有接受数据的能力,但是已经无法发送数据,但是也有一种可能是,客户端一直处于FIN_WAIT_2状态,而服务器则一直处于WAIT_CLOSE状态,而直到应用层来决定关闭这个状态。

            

5.RST,同时打开和同时关闭

            

RST是另一种关闭连接的方式,应用程序应该可以判断RST包的真实性,即是否为异常中止。而同时打开和同时关闭则是两种特殊的TCP状态,发生的概率很小。

            

6.TCP服务器设计

            

前面曾经讲述过UDP的服务器设计,可以发现UDP的服务器完全不需要所谓的并发机制,它只要建立一个数据输入队列就可以。但是TCP不同,TCP服务器对于每一个连接都需要建立一个独立的进程(或者是轻量级的,线程),来保证对话的独立性。所以TCP服务器是并发的。而且TCP还需要配备一个呼入连接请求队列(UDP服务器也同样不需要),来为每一个连接请求建立对话进程,这也就是为什么各种TCP服务器都有一个最大连接数的原因。而根据源主机的IP和端口号码,服务器可以很轻松的区别出不同的会话,来进行数据的分发。

            

            

            

            

            

Linux 查看磁盘分区、文件系统、使用情况的命令和相关工具介绍

作者:北南南北
来自:LinuxSir.Org
提要:Linux 磁盘分区表、文件系统的查看、统计的工具很多,有些工具是多功能的,不仅仅是查看磁盘的分区表,而且也能进行磁盘分区的操作;但在本文,我们只讲磁盘分区的查看,以及分区的使用情况的查看;本文只是给新手上路之用;关于分区工具的操作,我将在以后做专门介绍;

此文目的:主要是向初学者介绍一下入门必备的一点基础知识,有了基础知识才能进阶;如果把所有的磁盘操作工具都放在一个文档里,大家看了也累;基于这种想法,所以我写文档的时候,就想让新手弟兄一目了解,能轻松点就轻松点;生活、工作和学习无不是如此;

操作环境:Fedora core 4.0 i686 & Slackware 10.1


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
正文
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


一、df 命令;

df 是来自于coreutils 软件包,系统安装时,就自带的;我们通过这个命令可以查看磁盘的使用情况以及文件系统被挂载的位置;

举例:

我们从中可以看到,系统安装在/dev/hda8 ;还有一个56G的磁盘分区/dev/sda1挂载在 /mnt/sda1中;

其它的参数请参考 man df


二、fdsik

fdisk 是一款强大的磁盘操作工具,来自util-linux软件包,我们在这里只说他如何查看磁盘分区表及分区结构;参数 -l ,通过-l 参数,能获得机器中所有的硬盘的分区情况;

[root@localhost beinan]# fdisk -l

Disk /dev/hda: 80.0 GB, 80026361856 bytes
255 heads, 63 sectors/track, 9729 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System
/dev/hda1 * 1 765 6144831 7 HPFS/NTFS
/dev/hda2 766 2805 16386300 c W95 FAT32 (LBA)
/dev/hda3 2806 7751 39728745 5 Extended
/dev/hda5 2806 3825 8193118+ 83 Linux
/dev/hda6 3826 5100 10241406 83 Linux
/dev/hda7 5101 5198 787153+ 82 Linux swap / Solaris
/dev/hda8 5199 6657 11719386 83 Linux
/dev/hda9 6658 7751 8787523+ 83 Linux

 

在上面Blocks中,表示的是分区的大小,Blocks的单位是byte ,我们可以换算成M,比如第一个分区/dev/hda1的大小如果换算成M,应该是6144831/1024=6000M,也就是6G左右,其实没有这么麻烦,粗略的看一下把小数点向前移动三位,就知道大约的体积有多大了;
System 表示的文件系统,比如/dev/hda1 是NTFS格式的;/dev/hda2 表示是fat32格式的文件系统;.

在此例中,我们要特别注意的是/dev/hda3分区,这是扩展分区;他下面包含着逻辑分区,其实这个分区相当于一个容器;从属于她的有 hda5,hda6,hda7,hda8,hda9 ;

我们还注意到一点,怎么没有hda4呢?为什么hda4没有包含在扩展分区?一个磁盘最多有四个主分区; hda1-4算都是主分区;hda4不可能包含在扩展分区里,另外扩展分区也算主分区;在本例中,没有hda4这个分区,当然我们可以把其中的一个分区设置为主分区,只是我当时分区的时候没有这么做而已;

再仔细统计一下,我们看一看这个磁盘是不是还有空间?hda1+hda2+hda3=实际已经分区的体积,所以我们可以这样算 hda1+hda2+hda3=6144831+16386300+39728745 = 62259876 (b),换算成M单位,小数点向前移三位,所以目前已经划分好的分区大约占用体积是62259.876(M),其实最精确的计算62259876/1024=60800.67(M);而这个磁盘大小是80.0 GB (80026361856byte),其实实际大小也就是78150.744(M);通过我们一系列的计算,我们可以得出这个硬盘目前还有使用的空间;大约还有18G未分区的空间;

fdisk -l 能列出机器中所有磁盘的个数,也能列出所有磁盘分区情况;比如:

 

[root@localhost beinan]# fdisk -l

Disk /dev/hda: 80.0 GB, 80026361856 bytes
255 heads, 63 sectors/track, 9729 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System
/dev/hda1 * 1 765 6144831 7 HPFS/NTFS
/dev/hda2 766 2805 16386300 c W95 FAT32 (LBA)
/dev/hda3 2806 7751 39728745 5 Extended
/dev/hda5 2806 3825 8193118+ 83 Linux
/dev/hda6 3826 5100 10241406 83 Linux
/dev/hda7 5101 5198 787153+ 82 Linux swap / Solaris
/dev/hda8 5199 6657 11719386 83 Linux
/dev/hda9 6658 7751 8787523+ 83 Linux

Disk /dev/sda: 60.0 GB, 60011642880 bytes
64 heads, 32 sectors/track, 57231 cylinders
Units = cylinders of 2048 * 512 = 1048576 bytes

Device Boot Start End Blocks Id System
/dev/sda1 1 57231 58604528 83 Linux

 

通过上面我们可以知道此机器有两块硬盘,我们也可以指定fdisk -l 来查看其中一个硬盘的分区情况;

 

[root@localhost beinan]# fdisk -l /dev/sda

Disk /dev/sda: 60.0 GB, 60011642880 bytes
64 heads, 32 sectors/track, 57231 cylinders
Units = cylinders of 2048 * 512 = 1048576 bytes

Device Boot Start End Blocks Id System
/dev/sda1 1 57231 58604528 83 Linux

通过上面情况可以知道,在/dev/sda 这个磁盘中,只有一个分区;使用量差不多是百分百了;

 

我们还可以来查看 /dev/hda的

[root@localhost beinan]# fdisk -l /dev/hda

 

自己试试看?

三、cfdisk 来自于util-linux的软件包;

cfdisk 也是一款不错的分区工具;在有些发行版中,此工具已经从util-linux包中剔除;cfdisk 简单易用是他的特点;和DOS中的fdisk 相似;在本标题中,我们只来解说如何查看机器的中的磁盘分区状况及所用的文件系统等;

查看磁盘分区的用法 cfdisk -Ps 磁盘设备名;
比如

[root@localhost beinan]cfdisk -Ps
[root@localhost beinan]cfdisk -Ps /dev/hda

[root@localhost beinan]cfdisk -Ps
Partition Table for /dev/hda

First Last
# Type Sector Sector Offset Length Filesystem Type (ID) Flag
-- ------- ----------- ----------- ------ ----------- -------------------- ----
1 Primary 0 23438834 63 23438835 Linux (83) Boot
2 Primary 23438835 156296384 0 132857550 Extended (05) None
5 Logical 23438835 155268224 63 131829390 Linux (83) None
6 Logical 155268225 156296384 63 1028160 Linux swap (82) None

 

我们只用的参数 -Ps,就列出了磁盘的分区情况;目前在Slackware Debian Mandrake 等主流发行版中存在cfdisk ,而fedora 4.0把这个小工具剔除了;有点可惜;这是我在Slackware中操作的;

如果您这样操作,就更直观了;

[root@localhost beinan]cfdisk 磁盘设备名

举例:

[root@localhost beinan]cfdisk /dev/hda

 

您所看到的是如下的模式:

 

cfdisk 2.12a

Disk Drive: /dev/hda
Size: 80026361856 bytes, 80.0 GB
Heads: 255 Sectors per Track: 63 Cylinders: 9729

Name Flags Part Type FS Type [Label] Size (MB)
-------------------------------------------------------------------------------------------
hda1 Boot Primary Linux ReiserFS 12000.69
hda5 Logical Linux ReiserFS 67496.65
hda6 Logical Linux swap 526.42

[Bootable] [ Delete ] [ Help ] [Maximize] [ Print ] [ Quit ]
[ Type ] [ Units ] [ Write ]

Toggle bootable flag of the current partition

 

您进入了cfdisk 的操作界面;用键盘移动指针到[Quit]就可以退出;


四、parted 功能不错的分区工具;在Fedora 4.0中有带,可以自己安装上;在此主题中,我们只说如何查看磁盘的分区情况;

调用方法简单,parted 默认是打开的设备是/dev/hda ,也可以自己指定;比如 parted /dev/hda 或/dev/sda 等;退出的方法是 quit

[root@localhost beinan]# parted

使用 /dev/hda
(parted) p
/dev/hda 的磁盘几何结构:0.000-76319.085 兆字节
磁盘标签类型:msdos
Minor 起始点 终止点 类型 文件系统 标志
1 0.031 6000.842 主分区 ntfs 启动
2 6000.842 22003.088 主分区 fat32 lba
3 22003.088 60800.690 扩展分区
5 22003.119 30004.211 逻辑分区 reiserfs
6 30004.242 40005.615 逻辑分区 reiserfs
7 40005.646 40774.350 逻辑分区 linux-swap
8 40774.381 52219.094 逻辑分区 ext3
9 52219.125 60800.690 逻辑分区 reiserfs

 

我们在partd 的操作面上,用p就可以列出当前磁盘的分区情况,如果想要查看其它磁盘,可以用 select 功能,比如 select /dev/sda ;

五、qtparted ,与parted 相关的软件还有qtparted ,也能查看到磁盘的结构和所用的文件系统,是图形化的;

[beinan@localhost ~]# qtparted

图形化的查看,一目了然;



六、sfdisk 也是一个分区工具,功能也多多;我们在这里只说他的列磁盘分区情况的功能;

[root@localhost beinan]# sfdisk -l

自己看看吧;

 

sfdisk 有几个很有用的功能;有兴趣的弟兄不妨看看;


七、partx 也简要的说一说,有些系统自带了这个工具,功能也简单,和fdisk 、parted、cfdisk 来说不值一提;不用也罢;

用法: partx 设备名

 

[root@localhost beinan]# partx /dev/hda
# 1: 63- 12289724 ( 12289662 sectors, 6292 MB)
# 2: 12289725- 45062324 ( 32772600 sectors, 16779 MB)
# 3: 45062325-124519814 ( 79457490 sectors, 40682 MB)
# 4: 0- -1 ( 0 sectors, 0 MB)
# 5: 45062388- 61448624 ( 16386237 sectors, 8389 MB)
# 6: 61448688- 81931499 ( 20482812 sectors, 10487 MB)
# 7: 81931563- 83505869 ( 1574307 sectors, 806 MB)
# 8: 83505933-106944704 ( 23438772 sectors, 12000 MB)
# 9: 106944768-124519814 ( 17575047 sectors, 8998 MB)

 

八、查看目前机器中的所有磁盘及分区情况:

[beinan@localhost ~]$ cat /proc/partitions
major minor #blocks name

3 0 78150744 hda
3 1 6144831 hda1
3 2 16386300 hda2
3 5 8193118 hda5
3 6 10241406 hda6
3 7 787153 hda7
3 8 11719386 hda8
3 9 8787523 hda9
8 0 58605120 sda
8 1 58604528 sda1

Linux下进程的各种状态

PROCESS STATE CODES
Here are the different values that the s, stat and state output specifiers
(header “STAT” or “S”) will display to describe the state of a process.

D Uninterruptible sleep (usually IO)  

不可中断的深度睡眠,一般由IO引起,同步IO在做读或写操作时,cpu不能做其它事情,只能等待,这时进程处于这种状态,如果程序采用异步IO,这种状态应该就很少见到了

R Running or runnable (on run queue)  

进程处于运行或就绪状态

S Interruptible sleep (waiting for an event to complete)

可接收信号的睡眠状态,sleep函数可演示这种状态

T Stopped, either by a job control signal or because it is being traced.

  被ctrl+z中断或被trace

W paging (not valid since the 2.6.xx kernel)

X dead (should never be seen)

进程已经完全死掉,不可能看见这种状态的

Z Defunct (“zombie”) process, terminated but not reaped by its parent.

进程已经终止,但是其父进程没有来及处理它,多进程写不好的话,这种状态是常见的

For BSD formats and when the stat keyword is used, additional characters may
be displayed:

< high-priority (not nice to other users)

N low-priority (nice to other users)

L has pages locked into memory (for real-time and custom IO)

s is a session leader

  进程组组长

l is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)

+ is in the foreground process group

find 命令的两种用法比较

我们经常会对find出来的文件做一些处理,这时有三种方法可以选择:

1.  直接把find的结果作为命令的参数

cmd ·find ….·

这样做看起来很简单,但是最大的缺点就是经常会出现参数太长的错误,因为find出来的文件太多了,所以我们可以参考第二种方法

2. 使用-exec 参数

find ….  -exec cmd {} \;

注意:} 和 \ 之间是至少有一个空格的; 且‘;’一定是要用\做转义的
这样做find就会把find到的文件一个一个地传给cmd来执行,如果cmd只能一个文件一个文嘉地处理,这样做是很好的,但是一般来讲处理文件的命令都不是这么单纯的,都可以一次处理多个文件,而我们却非要一个一个地提供参数就显得效率低下了,下面看第三种写法

3.  使用xargs命令

find … | xargs cmd

这样xargs会在让cmd不出现参数太长的前提下,一次提供给cmd更多的参数,这就比用exec效率高了

[color=#FF0000]注意:用find命令时,正则匹配一定要用引号,比如:find / -name ‘a*’ 查找a打头的文件,如果没有引号(单双都行)的话,*将扩展为当前目录下的所有文件名或目录名

awk 中文手册

awk 命令
用途
在文件中查找与模式匹配的行,然后在它们上面执行特定的操作。
语法
awk [ -F Ere ] [ -v Assignment ] … { -f ProgramFile | ‘Program’ } [ [ File …
| Assignment … ] ] …
描述
awk 命令利用一组用户提供的指令来将一组文件和用户提供的扩展正则表达式比较,一次一行。然后在任何与扩展正则表达式匹配的行上执行操作。awk
处理的最大记录大小为 10KB。
awk 命令的模式搜索比 grep 命令的搜索更常用,且它允许用户在输入文本行上执行多个操作。awk
命令编程语言不需要编译,并允许用户使用变量、数字函数、字符串函数和逻辑运算符。
awk 命令受到 LANG、LC_ALL、LC_COLLATE、LC_CTYPE、LC_MESSAGES、LC_NUMERIC、NLSPATH 和 PATH
环境变量的影响。
本章中包括以下主题:
awk 命令的输入
awk 命令的输出
通过记录和字段的文件处理
awk 命令编程语言
   模式
   操作
   变量
   特殊变量
标志
示例
awk 命令的输入
awk 命令采取两种类型的输入:输入文本文件和程序指令。
输入文本文件
搜索和操作在输入文本文件上执行。文件如下指定:
在命令行指定 File 变量。
修改特殊变量 ARGV 和 ARGC。
在缺省 File 变量的情况下提供标准输入。
如果用 File 变量指定多个文件,则文件以指定的顺序处理。
程序指令
用户提供的指令控制 awk 命令的操作。这些指令来自命令行的‘Program’变量或来自用 -f 标志和 ProgramFile
变量一起指定的文件。如果指定多个程序文件,这些文件以指定的顺序串联,且使用指令的生成的顺序。
awk 命令的输出
awk 命令从输入文本文件中的数据产生三种类型的输出:
选定的数据可以打印至标准输出,此输出完全同于输入文件。
输入文件的选定部分可以更改。
选定数据可以更改并可打印至标准输出,此输出可以同于或不同于输入文件的内容。
可以在同一个文件上执行所有三种类型的输出。awk 命令是别的编程语言允许用户重定向输出。
通过记录和字段的文件处理
文件以下列方式处理:
awk 命令扫描它的指令,并执行任何指定为在读取输入前发生的操作。
awk 编程语言中的 BEGIN 语句允许用于指定在读取第一个记录前要执行的一组指令。这对于初始化特殊变量特别有用。
从输入文件读取一个记录。
记录是由记录分隔符隔开的一组数据。记录分隔符的缺省值是换行字符,它使文件中的每一行成为一个单独的记录。记录分隔符可以通过设置 RS 特殊变量来更改。
记录是相对于 awk 命令的指令指定的每种模式比较。
命令指令可以指定应比较记录内的特定字段。缺省情况下,字段由空白区(空格或跳格)隔开。每个字段由一个字段变量表示。记录中的第一个字段指定为 $1
变量,第二个字段指定为 $2 变量,以此类推。整个记录指定为 $0 变量。字段分隔符可以通过在命令行使用 -F 标志或通过设置 FS 特殊变量来更改。FS
特殊变量可以设置为下列值:空格、单个字符或扩展正则表达式。
如果一个记录与一个模式相匹配,则任何与该模式相关的操作都在该记录上执行。
在记录和每个模式比较且执行了所有指定操作以后,从输入读取下一个记录;在从输入文件读取所有的记录之前,该进程重复。
如果已经指定了多个输入文件,则下一个文件打开,且在读取所有的输入文件之前,该进程重复。
在读取了最后一个文件中的最后一个记录后,awk 命令执行任何指定为在输入处理后发生的指令。
awk 编程语言中的 END 语句允许用户指定在读取最后一个记录后要执行的操作。这对于发送有关 awk 命令完成了什么工作的消息特别有用。
awk 命令编程语言
awk 命令编程语言由以下格式的语句构成:
Pattern { Action }
如果一个记录与指定模式相匹配,或包含与该模式匹配的字段,则执行相关的操作。可以指定没有操作的模式,这种情况下,包含该模式的整行写至标准输出。为每个输入记录执行指定的没有模式的操作。
模式
在 awk 命令语言语法中使用四种类型的模式:
正则表达式
关系表达式
模式的组合
BEGIN 和 END 模式
正则表达式
awk 命令使用的扩展正则表达式类似于 grep 或 egrep 命令使用的表达式。扩展正则表达式的最简单的形式就是包括在斜杠中的一串字符。例如,假定一个名为
testfile 的文件具有以下内容:
smawley, andy
smiley, allen
smith, alan
smithern, harry
smithhern, anne
smitters, alexis
输入以下一行命令:
awk ‘/smi/’ testfile
将把包含 smi 字符串的具体值的所有记录打印至标准输出。在这个示例中,awk 命令的程序 ‘/smi/’ 是一个没有操作的模式。输出是:
smiley, allen
smith, alan
smithern, harry
smithhern, anne
smitters, alexis
以下特殊字符用于形成扩展正则表达式:
     字符功能
     +指定如果一个或多个字符或扩展正则表达式的具体值(在 +(加号)前)在这个字符串中,则字符串匹配。命令行:
awk ‘/smith+ern/’ testfile
     将包含字符 smit,后跟一个或多个 h 字符,并以字符 ern 结束的字符串的任何记录打印至标准输出。此示例中的输出是:
smithern, harry
smithhern, anne

     ?指定如果零个或一个字符或扩展正则表达式的具体值(在 ?(问号)之前)在字符串中,则字符串匹配。命令行:
awk ‘/smith?/’ testfile
     将包含字符 smit,后跟零个或一个 h 字符的实例的所有记录打印至标准输出。此示例中的输出是:
smith, alan
smithern, harry
smithhern, anne
smitters, alexis

     |指定如果以 |(垂直线)隔开的字符串的任何一个在字符串中,则字符串匹配。命令行:
awk ‘/allen
|
alan /’ testfile
     将包含字符串 allen 或 alan 的所有记录打印至标准输出。此示例中的输出是:
smiley, allen
smith, alan

     ( )在正则表达式中将字符串组合在一起。命令行:
awk ‘/a(ll)?(nn)?e/’ testfile
     将具有字符串 ae 或 alle 或 anne 或 allnne 的所有记录打印至标准输出。此示例中的输出是:
smiley, allen
smithhern, anne

     {m}指定如果正好有 m 个模式的具体值位于字符串中,则字符串匹配。命令行:
awk ‘/l{2}/’ testfile
     打印至标准输出
smiley, allen

     {m,}指定如果至少 m 个模式的具体值在字符串中,则字符串匹配。命令行:
awk ‘/t{2,}/’ testfile
     打印至标准输出:
smitters, alexis

     {m, n}指定如果 m 和 n 之间(包含的 m 和 n)个模式的具体值在字符串中(其中m <= n),则字符串匹配。命令行:
awk ‘/er{1, 2}/’ testfile
     打印至标准输出:
smithern, harry
smithern, anne
smitters, alexis

     [String]指定正则表达式与方括号内 String 变量指定的任何字符匹配。命令行:
awk ‘/sm[a-h]/’ testfile
     将具有 sm 后跟以字母顺序从 a 到 h 排列的任何字符的所有记录打印至标准输出。此示例的输出是:
smawley, andy

     [^ String]在 [ ](方括号)和在指定字符串开头的 ^ (插入记号) 指明正则表达式与方括号内的任何字符不匹配。这样,命令行:
awk ‘/sm[^a-h]/’ testfile
     打印至标准输出:
smiley, allen
smith, alan
smithern, harry
smithhern, anne
smitters, alexis

     ~,!~表示指定变量与正则表达式匹配(代字号)或不匹配(代字号、感叹号)的条件语句。命令行:
awk ‘$1 ~ /n/’ testfile
     将第一个字段包含字符 n 的所有记录打印至标准输出:
smithern, harry
smithhern, anne

     ^指定字段或记录的开头。命令行:
awk ‘$2 ~ /^h/’ testfile
     将把字符 h 作为第二个字段的第一个字符的所有记录打印至标准输出。此示例中的输出是:
smithern, harry

     $指定字段或记录的末尾。命令行:
awk ‘$2 ~ /y$/’ testfile
     将把字符 y 作为第二个字段的最后一个字符的所有记录打印至标准输出。此示例中的输出是:
smawley, andy
smithern, harry

     .(句号)表示除了在空白末尾的终端换行字符以外的任何一个字符。命令行:
awk ‘/a..e/’ testfile
     将具有以两个字符隔开的字符 a 和 e 的所有记录打印至标准输出。此示例中的输出是:
smawley, andy
smiley, allen
smithhern, anne

     *(星号)表示零个或更多的任意字符。命令行:
awk ‘/a.*e/’ testfile
     将具有以零个或更多字符隔开的字符 a 和 e 打印至标准输出。此示例中的输出是:
smawley, andy
smiley, allen
smithhern, anne
smitters, alexis

     \ (反斜杠)转义字符。当位于在扩展正则表达式中具有特殊含义的任何字符之前时,转义字符除去该字符的任何特殊含义。例如,命令行:
/a\/\//
     将与模式 a //
     匹配,因为反斜杠否定斜杠作为正则表达式定界符的通常含义。要将反斜杠本身指定为字符,则使用双反斜杠。有关反斜杠及其使用的更多信息,请参阅以下关于转义序列的内容。

识别的转义序列
awk 命令识别大多数用于 C 语言约定中的转义序列,以及 awk 命令本身用作特殊字符的几个转义序列。转义序列是:
     转义序列表示的字符
     \”\”(双引号)
     \//(斜杠)字符
     \ddd其编码由 1、2 或 3 位八进制整数表示的字符,其中 d 表示一个八进制数位
     \\\ (反斜杠) 字符
     \a警告字符
     \b退格字符
     \f换页字符
     \n换行字符(请参阅以下的注)
     \r回车字符
     \t跳格字符
     \v垂直跳格

注:除了在 gsub、match、split 和 sub
内置函数中,扩展正则表达式的匹配都基于输入记录。记录分隔符字符(缺省情况下为换行字符)不能嵌套在表达式中,且没与记录分隔符字符匹配的表达式。如果记录分隔符不是换行字符,则可与换行字符匹配。在指定的四个内置函数中,匹配基于文本字符串,且任何字符(包含记录分隔符)可以嵌套在模式中,这样模式与适当的字符相匹配。然而,用
awk 命令进行的所有正则表达式匹配中,在模式使用一个或多个 NULL(空)字符将生成未定以的结果。
关系表达式
关系运算符 <(小于)、>(大于)、<=(小于或等于)、>=(大于或等于)、= =(等于)和 !=(不等于)可用来形成模式。例如,模式:
$1 < $4
将与第一个字段小于第四个字段的记录匹配。关系运算符还和字符串值一起使用。例如:
$1 =! “q”
将与第一个字段不是 q 的所有记录匹配。字符串值还可以根据校对值匹配。例如:
$1 >= “d”
将与第一个字段以字符 a、b、c 或 d 开头的所有记录匹配。如果未给出其它信息,则字段变量作为字符串值比较。
模式的组合
可以使用三种选项组合模式:
范围由两种以 ,(逗号)隔开的模式指定。操作在每个以匹配第一个模式的记录开始的每个记录上执行,并通过匹配第二个模式的记录(包含此记录)继续。例如:
/begin/,/end/
与包含字符串 begin 的记录以及该记录和包含字符串 end 之间的所有记录(包含包括字符串 end 的记录)匹配。
括号 ( ) 将模式组合在一起。
布尔运算符 ||(或)&&(和)以及 !(不)将模式组合成如果它们求值为真则匹配,否则不匹配的表达式。例如,模式:
$1 == “al” && $2 == “123”
与第一个字段是 al 且第二个字段是 123 的记录匹配。
BEGIN 和 END 模式
用 BEGIN 模式指定的操作在读取任何输入之前执行。用 END 模式指定的操作在读取了所有输入后执行。允许多个 BEGIN 和 END
模式,并以指定的顺序处理它们。在程序语句中 END 模式可以在 BEGIN 模式之前。如果程序仅由 BEGIN 语句构成,则执行操作且不读取输入。如果程序仅由
END 语句构成,则在任何操作执行前读取所有输入。
操作
有多种类型的操作语句:
操作语句
内置函数
用户定义的函数
条件语句
输出操作
操作语句
操作语句括在 { } (花括号) 中。如果语句指定为没有模式,则它们在每个记录上执行。在括号里可以指定多个操作,但操作间必须以换行字符或
;(分号),且语句以它们出现的顺序处理。操作语句包含:
     算术语句
     算术运算符 +(加号), – (减号), / (除号), ^ (幂), * (乘号), % (系数)用于格式:
表达式 运算符 表达式
     这样语句为:
$2 = $1 ^ 3
     将第一个升为三次方的字段的值指定给第二个字段。
     一元语句
     一元 -(减号)和一元 +(加号)如在 C 编程语言中操作:
+Expression 或 -Expression

     增量和减量语句
     增量前语句和减量前语句如在 C 编程语言中操作:
++Variable 或 –Variable
     增量后语句和减量后语句如在 C 编程语言中操作:
Variable++ 或 Variable–

     赋值语句
     赋值运算符 +=(加)、-=(减)、/=(除)和 *=(乘)如在 C 编程语言中操作,格式为:
Variable += Expression
Variable -= Expression
Variable /= Expression
Variable *= Expression
     例如,语句:
$1 *= $2
     将字段变量 $1 乘以字段变量 $2,然后将新值指定给 $1。
     赋值运算符 ^=(幂)和 %=(系数)具有以下格式:
Variable1^=Expression1
     和
Variable2%=Expression2
     并且它们等同于 C 编程语言语句:
Variable1=pow(Variable1, Expression1)
     和
Variable2=fmod(Variable2, Expression2)
     其中 pow 是 pow 子例程而 fmod 是 fmod 子例程。
     字符串串联语句
     字符串值可以通过紧挨着陈述来串联。例如:
$3 = $1 $2
     将字段变量 $1 和 $2 中的字符串的串联指定给字段变量 $3。

内置函数
awk 命令语言使用算术函数、字符串函数和一般函数。如果打算编写一个文件,且稍后在同一个程序里读取它,则 close 子例程语句是必需的。
算术函数
以下算术函数执行与 C 语言中名称相同的子例程相同的操作:
     atan2( y, x )返回 y/x 的反正切。
     cos( x )返回 x 的余弦;x 是弧度。
     sin( x )返回 x 的正弦;x 是弧度。
     exp( x )返回 x 幂函数。
     log( x )返回 x 的自然对数。
     sqrt( x )返回 x 平方根。
     int( x )返回 x 的截断至整数的值。
     rand( )返回任意数字 n,其中 0 <= n < 1。
     srand( [Expr] )将 rand 函数的种子值设置为 Expr 参数的值,或如果省略 Expr 参数则使用某天的时间。返回先前的种子值。

字符串函数
字符串函数是:
     gsub( Ere, Repl, [ In ] )除了正则表达式所有具体值被替代这点,它和 sub 函数完全一样地执行,。
     sub( Ere, Repl, [ In ] )用 Repl 参数指定的字符串替换 In 参数指定的字符串中的由 Ere
     参数指定的扩展正则表达式的第一个具体值。sub 函数返回替换的数量。出现在 Repl 参数指定的字符串中的 &(和符号)由 In 参数指定的与
     Ere 参数的指定的扩展正则表达式匹配的字符串替换。如果未指定 In 参数,缺省值是整个记录($0 记录变量)。
     index( String1, String2 )在由 String1 参数指定的字符串(其中有出现 String2 指定的参数)中,返回位置,从
     1 开始编号。如果 String2 参数不在 String1 参数中出现,则返回 0(零)。
     length [(String)]返回 String 参数指定的字符串的长度(字符形式)。如果未给出 String 参数,则返回整个记录的长度($0
     记录变量)。
     blength [(String)]返回 String 参数指定的字符串的长度(以字节为单位)。如果未给出 String
     参数,则返回整个记录的长度($0 记录变量)。
     substr( String, M, [ N ] )返回具有 N 参数指定的字符数量子串。子串从 String 参数指定的字符串取得,其字符以 M
     参数指定的位置开始。M 参数指定为将 String 参数中的第一个字符作为编号 1。如果未指定 N,则子串的长度将是 M 参数指定的位置到
     String 参数的末尾 的长度。
     match( String, Ere )在 String 参数指定的字符串(Ere 参数指定的扩展正则表达式出现在其中)中返回位置(字符形式),从
     1 开始编号,或如果 Ere 参数不出现,则返回 0(零)。RSTART 特殊变量设置为返回值。RLENGTH
     特殊变量设置为匹配的字符串的长度,或如果未找到任何匹配,则设置为 -1(负一)。
     split( String, A, [Ere] )将 String 参数指定的参数分割为数组元素 A[1], A[2], . . .,
     A[n],并返回 n 变量的值。此分割可以通过 Ere 参数指定的扩展正则表达式进行,或用当前字段分隔符 FS 特殊变量)来进行(如果没有给出
     Ere 参数)。除非上下文指明特定的元素还应具有一个数字值,否则 A 数组中的元素用字符串值来创建。
     tolower( String )返回 String 参数指定的字符串,字符串中每个大写字符将更改为小写。大写和小写的映射由当前语言环境的
     LC_CTYPE 范畴定义。
     toupper( String )返回 String 参数指定的字符串,字符串中每个小写字符将更改为大写。大写和小写的映射由当前语言环境的
     LC_CTYPE 范畴定义。
     sprintf(Format, Expr, Expr, . . . )根据 Format 参数指定的 printf 子例程格式字符串来格式化
     Expr 参数指定的表达式并返回最后生成的字符串。

一般函数
一般函数是:
     close( Expression )用同一个带字符串值的 Expression 参数来关闭由 print 或 printf 语句打开的或调用
     getline 参数打开的文件或管道。如果文件或管道成功关闭,则返回 0;其它情况下返回非零值。如果打算写一个文件,并稍后在同一个程序中读取文件,则
     close 语句是必需的。
     system(Command )执行 Command 参数指定的命令,并返回出口状态。等同于 system 子例程。
     Expression | getline [ Variable ]从来自 Expression
     参数指定的命令的输出中通过管道传送的流中读取一个输入记录,并将该记录的值指定给 Variable 参数指定的变量。如果当前未打开江
     Expression 参数的值作为其命令名称的流,则创建流。创建的流等同于调用 popen 子例程,此时 Command 参数取
     Expression 参数的值且 Mode 参数设置为一个是 r 的值。只要流保留打开且 Expression 参数求得同一个字符串,则对
     getline 函数的每次后续调用读取另一个记录。如果未指定 Variable 参数,则 $0 记录变量和 NF 特殊变量设置为从流读取的记录。
     getline [ Variable ] < Expression从 Expression 参数指定的文件读取输入的下一个记录,并将
     Variable 参数指定的变量设置为该记录的值。只要流保留打开且 Expression 参数对同一个字符串求值,则对 getline
     函数的每次后续调用读取另一个记录。如果未指定 Variable 参数,则 $0 记录变量和 NF 特殊变量设置为从流读取的记录。
     getline [ Variable ]将 Variable 参数指定的变量设置为从当前输入文件读取的下一个输入记录。如果未指定 Variable
     参数,则 $0 记录变量设置为该记录的值,还将设置 NF、NR 和 FNR 特殊变量。

注:所有 getline 函数的格式对于成功输入返回 1,对于文件结束返回零,对于错误返回 -1。
用户定义的函数
用户定义的函数以下列格式说明:
function Name (Parameter, Parameter,…)  { Statements }
函数可以指向 awk 命令程序中的任何位置,且它的使用可以优先于它的定义。此函数的作用域是全局的。
函数参数可以是标量或数组。参数名称对函数而言是本地的;所有其它变量名称都是全局的。同一个名称不应用作不同的实体;例如,一个参数不能即用作函数名称又用作特殊变量。具有全局作用域的变量不应共享一个函数的名称。同个作用域中的标量和数组不应具有同一个名称。
函数定义中的参数数量不必和调用函数时使用的参数数量匹配。多余的形式参数可用作本地变量。额外的标量初始化后具有等同于空字符串和数字值为
0(零)的字符串值;额外的数组参数初始化为空数组。
当调用函数时,函数名称和左括号之间没有空格。函数调用可以是嵌套的或循环的。从任何嵌套的或循环函数函数调用返回时,所有调用函数的参数的值应保持不变,除了引用传送的数组参数。return
语句可用于返回一个值。
在函数定义内,在左 { (花括号) 之前和右 } (花括号) 之后的换行字符是可选的。
函数定义的一个示例是:
function average ( g,n)
{
       for (i in g)
          sum=sum+g
       avg=sum/n
       return avg
}
数组 g 和变量 n 以及数组中的元素个数传递给函数 average。然后函数获得一个平均值并返回它。
条件语句
awk 命令编程语言中的大部分条件语句和 C 编程语言中的条件语句具有相同的语法和功能。所有条件语句允许使用{ } (花括号)
将语句组合在一起。可以在条件语句的表达式部分和语句部分之间使用可选的换行字符,且换行字符或 ;(分号)用于隔离 { } (花括号) 中的多个语句。C
语言中的六种条件语句是:
     if需要以下语法:
     if ( Expression ) { Statement } [ else Action ]
     while需要以下语法:
     while ( Expression ) { Statement }
     for需要以下语法:
     for ( Expression ; Expression ; Expression ) { Statement }
     break当 break 语句用于 while 或 for 语句时,导致退出程序循环。
     continue当 continue 语句用于 while 或 for 语句时,使程序循环移动到下一个迭代。

awk 命令编程语言中的五种不遵循 C 语言规则的条件语句是:
     for…in需要以下语法:
     for ( Variable in Array ) { Statement }
     for…in 语句将 Variable 参数设置为 Array 变量的每个索引值,一次一个索引且没有特定的顺序,并用每个迭代来执行
     Statement 参数指定的操作。请参阅 delete 语句以获得 for…in 语句的示例。
     if…in需要以下语法:
     if ( Variable in Array ) { Statement }
     if…in 语句搜索是否存在的 Array 元素。如果找到 Array 元素,就执行该语句。
     delete需要以下语法:
     delete Array [ Expression ]
     delete 语句删除 Array 参数指定的数组元素和 Expression 参数指定的索引。例如,语句:
for (i in g)
  delete g;
     将删除 g[] 数组的每个元素。
     exit需要以下语法:
     exit [Expression]
     exit 语句首先调用所有 END 操作(以它们发生的顺序),然后以 Expression 参数指定的出口状态终止 awk 命令。如果 exit
     语句在 END 操作中出现,则不调用后续 END 操作。
     #需要以下语法:
     # Comment
     # 语句放置注释。注释应始终以换行字符结束,但可以在一行上的任何地方开始。
     next停止对当前输入记录的处理,从下一个输入记录继续。

输出语句
awk 命令编程语言的两种输出语句是:
     print需要以下语法:
     print [ ExpressionList ] [ Redirection ] [ Expression ]
     print 语句将 ExpressionList 参数指定的每个表达式的值写至标准输出。每个表达式由 OFS 特殊变量的当前值隔开,且每个记录由
     ORS 特殊变量的当前值终止。
     可以使用 Redirection 参数重定向输出,此参数可指定用 >(大于号)、>>(双大于号)和
     |(管道)进行的三种输出重定向。Redirection 参数如果重定向输出,而 Expression 参数是文件的路径名称(当
     Redirection 参数是 > 或 >> 时)或命令的名称(当 Redirection 参数是 | 时)。
     printf需要以下语法:
     printf Format [ , ExpressionList ] [ Redirection ] [ Expression ]
     printf 语句将 ExpressionList 参数指定的表达式以 Format 参数指定的格式写至标准输出。除了 c
     转换规范(%c)不同外,printf 语句和 printf 命令起完全相同的作用。Redirection 和 Expression 参数与在
     print 语句中起相同的作用。
     对于 c
     转换规范:如果自变量具有一个数字值,则编码是该值的字符将输出。如果值是零或不是字符集中的任何字符的编码,则行为未定义。如果自变量不具有数字值,则输出字符串值的第一个字符;如果字符串不包含任何字符,则行为未定义。

注:如果 Expression 参数为 Redirection 参数指定一个路径名称,则 Expression 参数将括在双引号中以确保将它当作字符串对待。
变量
变量可以是标量、字段变量、数组或特殊变量。变量名称不能以数字开始。
变量可仅用于引用。除了函数参数以外,它们没有明确说明。未初始化的标量变量和数组元素具有一个为 0(零)的数字值和一个为空字符串(” “)的字符串值。
根据上下文,变量呈现出数字或字符串值。每个变量可以具有数字值和/或字符串值。例如:
x = “4” + “8”
将值 12 指定给变量 x。对于字符串常量,表达式应括在 ” “(双引号)中。
数字和字符串间没有显式转换。要促使将表达式当作一个数字,向它添加 0(零)。要促使将表达式当作一个字符串,则添加一个空字符串(” “)。
字段变量
字段变量由 $(美元符号)后跟一个数字或数字表达式来表示。记录中的第一个字段指定为 $1 变量,第二个字段指定为 $2,以次类推。$0
字段变量指定给整个记录。新字段可以通过指定一个值给它们来创建。将一个值指定给不存在的字段(即任何大于 $NF
字段变量的当前值的字段)将促使创建任何干扰字段(指定为空字符串),增加 NF 特殊变量的值,并促使重新计算 $0 记录变量。新字段由当前字段分隔符(FS
特殊变量的值)隔开。空格和跳格是缺省字段分隔符。要更改字段分隔符,请使用 -F 标志或 在 awk 命令程序中为 FS 特殊变量指定另一个值。
数组
数组初始为空且它们大小可动态更改。数组由一个变量和在 [ ](方括号)中的下标来表示。下标或元素标识符可以是几个字符串,它们提供了一种相关数组能力。例如,程序:
/red/  { x[“red”]++ }
/green/ { y[“green”]++ }
增加 red 计数器和 green 计数器的计数。
数组可以用一个以上的下标来建立索引,类似于一些编程语言中的多维数组。因为 awk 命令的编程数组实际上一维的,通过串联各独立表达式的字符串值(每个表达式由
SUBSEP 环境变量的值隔开)来将以逗号隔开的下标转换为单个字符串。所以,以下两个索引操作是等同的:
x[expr1, expr2,…exprn]

x[expr1SUBSEPexpr2SUBSEP…SUBSEPexprn]
当使用 in 运算符时,一个多维 Index 值应包含在圆括号之中。除了 in 运算符,任何对不存在数组元素的引用将自动创建该元素。
特殊变量
以下变量对于 awk 命令具有特殊含义:
     ARGCARGV 数组中的元素个数。此值可以更改。
     ARGV其每个成员包含 File 变量之一或 Assignment 变量之一的数组按序从命令行取出,并从 0(零)编号至 ARGC
     -1。当每个输入文件完成时,ARGV 数组的下一个成员提供下一个输入文件的名称,除非:
       下一个成员是 Assignment 语句,这种情况下对赋值求值。
       下一个成员具有空值,这种情况下跳过该成员。程序可以通过设置 ARGV 数组的包含该输入文件的成员设置为一个空值来跳过所选的输入文件。
       下一个成员是 ARGV [ARGC -1] 的当前值,awk 命令将此成员解释为输入文件的末尾。

     CONVFMT将数字转换为字符串的 printf 格式(除了使用 OFMT 特殊变量的输出语句)。缺省值为“%.6g”。
     ENVIRON表示运行 awk 命令的环境的数组。该数组的每个元素在以下格式中:
     ENVIRON [ “Environment VariableName” ] = EnvironmentVariableValue
     当 awk 命令开始执行时设置这些值,且到执行结束前一直使用该变量,不考虑 ENVIRON 特殊变量的任何修改。
     FILENAME当前输入文件的路径名称。在执行 BEGIN 操作的过程中,FILENAME 的值未定义。在执行 END
     操作的过程中,该值是处理的最后一个输入文件的名称。
     FNR当前文件中的当前输入记录的个数。
     FS输入字段分隔符。缺省值是空格。如果输入字段分隔符是空格,则任何数目的语言环境定义的空格可以分隔字段。FS 特殊变量可以有两种附加的值:
       如果 FS 设置为单个字符,则字段由该字符的每个单个具体值隔开。
       如果 FS 位置为一个扩展正则表达式,则字段由与扩展正则表达式匹配的每个序列的具体值隔开。

     NF当前记录中的字段个数,最大数 99 个。在 BEGIN 操作中,除非先前发出不带 Variable 参数的 getline 函数,否则 NF
     特殊变量未定义。在 END 操作中,除非在输入 END 操作之前发出不带 Variable 参数的后续的、重定向的 getline 函数,否则 NF
     特殊变量保留它为读取的最后一个记录而具有的值。
     NR当前输入记录的个数。在 BEGIN 操作中,NR 特殊变量的值是 0(零)。在 END 操作中,值是最后处理的记录的编号。
     OFMT在输出语句中将数字转换为字符串的 printf 格式。缺省值为“%.6g”。
     OFS输出字段分隔符(缺省值是空格)。
     ORS输出记录分隔符(缺省值是换行字符)。
     RLENGTH由 match 函数来匹配的字符串的长度。
     RS输入记录分隔符(缺省值是换行字符)。如果 RS
     特殊变量为空,则记录以一个或多个空行的序列隔开;第一个空行或最后一个空行在输入的开始和结束都不会产生空记录;换行字符始终是一个字段分隔符,不考虑
     FS 特殊变量的值。
     RSTART由 match 函数来匹配的字符串的起始位置,从 1 开始编号。等同于 match 函数的返回值。
     SUBSEP隔开多个下标。缺省值是 \031。

标志
     -f ProgramFile从 ProgramFile 变量指定的文件获取 awk 命令的指令。如果多次指定 -f
     标志,则文件的串联(按指定的顺序)将用作指令集。
     -F Ere请使用 Ere 变量指定的扩展正则表达式作为字段分隔符。缺省字段分隔符是空格。
     -v Assignment将值指定给 awk 命令编程语言的变量。Assignment 参数的格式是 Name = Value。Name
     部分指定变量的名称并可以是任何下划线、数字或字母字符的组合,但它必须以字母字符或下划线开头。Value
     部分也由下划线、数字和字母数字组成,且前面和后面都有一个 “(双引号字符,类似于字符串值)。如果 Value 部分是数字,则也将为变量指定数字值。
     -v 标志指定的赋值在执行 awk 命令程序的任何部分之前发生,包含 BEGIN 节。
     Assignment将值指定给 awk 命令编程语言的变量。该值和带有 -v 标志的 Assignment
     变量具有相同的格式和功能(除了两者处理的时间不同以外)。Assignment 参数在处于命令行时跟在其后的输入文件(由 File
     变量指定)之前处理。如果指定 Assignment 参数仅优先于多个输入文件的第一个,则赋值在 BEGIN 节后(如果有)就处理。如果
     Assignment 参数出现在最后一个文件后,则在 END 节(如果有)之前处理赋值。如果不指定输入文件,则当读取了标准输入时处理赋值。
     File指定包含要处理的输入的文件的名称。如果不指定 File 变量,或指定了 -(减号),则处理标准输入。
     ‘Program’包含 awk 命令的指令。如果不指定 -f 标志,Program 变量应该是命令行上的第一个项。它应括在 ‘ ‘(单引号)中。

出口状态
该命令返回以下出口值:
     0成功完成。
     >0发生错误。

可以通过使用 exit [ Expression ] 条件语句来更改程序中的出口状态。
示例
要显示长于 72 个字符的文件的行,请输入:
awk  ‘length  >72’  chapter1
这选择 chapter1 文件中长于 72 个字符的每一行,并将这些行写至标准输出,因为未指定 Action。制表符以 1 个字符计数。
要显示字 start 和 stop 之间的所有行,包含“start”和“stop”,请输入:
awk  ‘/start/,/stop/’  chapter1
要运行一个处理文件 chapter1 的 awk 命令程序 sum2.awk,请输入:
awk  -f  sum2.awk  chapter1
以下程序,sum2.awk,计算了输入文件 chapter1 中的第二列的数字的总和与平均值:
   {
      sum += $2
   }
END {
      print “Sum: “, sum;
      print “Average:”, sum/NR;
   }
第一个操作将每行的第二个字段的值添加至变量 sum。当第一次被引用时,所有的变量都初始化为数字值 0(零)。第二个操作前的模式 END
使那些操作在读取了所有输入文件之后才执行。用于计算平均值的 NR 特殊变量是一个指定已经读取的记录的个数的特殊变量。
要以相反顺序打印前两个字段,请输入:
awk ‘{ print $2, $1 }’ chapter1
以下 awk 的程序 sum3.awk 打印文件 chapter2
的前两个字段(输入字段由逗号和/或空格和跳格隔开),然后合计第一列的数字,并打印出总和与平均值:
BEGIN  {FS = “,|[ \t]+”}
      {print $1, $2}
      {s += $1}
END    {print “sum is”,s,”average is”, s/NR }      

其它相关文章:
[color=#FF0000]http://linuxfire.com.cn/~lily/awk.html

[color=#FF0000]http://linuxfire.com.cn/~lily/awk.html