一个Shell程序的性能优化Unix系统

2024-04-22

一个Shell程序的性能优化Unix系统(精选8篇)

篇1:一个Shell程序的性能优化Unix系统

本文Shell程序运行环境: ◆程序运行环境Redhat Linux As3 ◆GNU bash, version 2.05b.0(1)-release (i386-redhat- linux -gnu) ◆代码清单:shellcode.txt 问题描述:有一个普通的通话话单文件(包括“计费号码”,“主叫号码”,“被叫号码”,“开始时间”

本文Shell程序运行环境:

◆程序运行环境Redhat Linux As3

◆GNU bash, version 2.05b.0(1)-release (i386-redhat-linux-gnu)

◆代码清单:shellcode.txt

问题描述:有一个普通的通话话单文件(包括“计费号码”,“主叫号码”,“被叫号码”,“开始时间”,“结束时间”,“时长”,“费用”等其它字段),要求根据另外一个号段配置文件(由“号段下限”和“号段上限”两个字段组成)将此话单文件进行分拣过虑,

分拣规则:如果通话话单文件中的“计费号码”位于号段文件的某个号段内,则将此条记录计入结果文件1,否则计入结果文件2。

通话话单文件样例:

901333|9013320003|9918128025|0814163420|20060814163450|30|20|00|01|005

9926645208|9926645208|9918188065|20060814163415|20060814163545|90|30|00|01|005

9934877207|9934877207|993697|20060814163620|20060814163930|190|50|00|01|005

......

......

号段配置文件样例:

9013305000,9013327999

9013767000,9013768999

9923670000,9923679999

9928998000,9928999999

9932310000,993239

9932333400,9932333599

9936034000,9936036999

9936084000,9936084999

9998537000,9998537999

9998620000,9998629999

9998690000,9998699999

例如:

对于通话话单文件的第一条记录中的“计费号码”为9013320000,此号码正好属于号段配置文件的第一个号段9013305000,9013327999中,即:条件9013305000<= 9013320000 <=9013327999成立,所以应该将通话话单文件的第一条记录计入结果文件1中;对于通话话单文件中的第二条记录的“计费号码”为9926645208它不属于号段文件中的任何一个段,所以应该将通话话单的第二条记录计入结果文件2中。

对于这样一个简单的问题首先想到的解决方法为:

解决方法1:

写一个双重循环,外层循环为逐条读取“通话话单文件”并获取每条记录的第一个字段的值“计费号码”,内层循环:根据外层循环获得的“计费号码”在“号段文件”中循环比较,判断此号码是否属于相应号段。

程序代码如下(省略了文件存在性判断等语句):

while read f

do

rg=“$(expr substr ${f} 1 10)”#取得“计费号码”存入变量org中

while read numseg

do

nglow=“$(expr substr ${numseg} 1 10 )”#将号段下限存入变量nglow

ngtop=“$(expr substr ${numseg} 12 10 )”#将号段上限存入变量ngtop

if [ “$org” > “$nglow”-a “$org” < $ngtop ]

#判断“计费号码”是否在此号段内

then

echo “${f}” >>./resultfile1.cdr #如果在此号段内,将此记录计入结果文件1中

else

echo “${f}” >>./resultfile2.cdr #如果不在此号段内,将此记录计入结果文件2中

fi

done < ./numseg.txt

done < ./rttest.txt

解决方法1对于号段文件和通话话单的记录数都比较少的情况下基本可以完成工作,但是当两个文件的记录数较多(例如号段文件>50条,话单文件>10000条)的时候,这种方法就会花费几个小时甚至几天的时间才能得出处理结果。此脚本程序执行慢的原因是对第二个循环内的比较运算只用了最简单的顺序比较方法,所以当号段文件的记录增多的时候,脚本的执行速度会急剧下降。

解决方法2:

将内层循环的逐个比较的方法改为二分查找法进行判断,程序代码如下:

#!/bin/bash

#Author Xshdate:08-15-2006

#程序中使用了二分查找法进行号码的范围判断

#为突出重点,省略了文件存在性判断和异常捕获以及帮助提示等程序语句

#程序的工作目录为当前目录

echo “Time:$(date)==>Strat to processing.........” #显示程序开始运行时间

while read numseg

do

tmplow=“${tmplow} $(expr substr ${numseg} 1 10 & >/dev/null ) ”

tmptop=“${tmptop} $(expr substr ${numseg} 12 10 & >/dev/null ) ”

done < ./numseg.txt

#读取号段文件,下限号段存入变量tmplow,上限号段存入变量tmptop

arr_lownug=(${tmplow}) #将下限号段存入数组arr_lownug

arr_topnug=(${tmptop})#将上限号段存入数组arr_topnug

#定义函数checknum,输入参数为需要检查的“计费号码”,输出参数为0或者1

#若checknum()输出为0 表示“计费号码” 不在号段文件的所有号段范围内

#若checknum()输出为1 表示“计费号码” 在号段文件的所有号段范围内

# checknum()函数中用二分搜索法进行号码的判断

checknum(){

thisnum=$1

ckresult=0

lowflag=0

topflag=$(expr ${#arr_lownug[*]} - 1 )#标注1

MaxIndex=$(expr ${#arr_topnug[*]} - 1 ) #标注2

midflag=0

midflag=$(expr ${topflag} / 2 )#标注3

if [ “${thisnum}” < “${arr_lownug[0]}” -o “${thisnum}” >

“${arr_topnug[${MaxIndex}]}”]

then

return 0

else

while [ “$lowflag” != “$midflag” ]

do

if[ “$thisnum” > “${arr_lownug[${midflag}]}” -o “$thisnum” ==

“${arr_lownug[${midflag}]}” ]

then

lowflag=${midflag}

midflag=$(expr `expr ${topflag} + ${lowflag}` / 2 ) #标注4

elif[“$thisnum”<“${arr_lownug[${midflag}]}” -o “$thisnum” ==

“${arr_lownug[${midflag}]}” ]

then

topflag=${midflag}

midflag=$(expr `expr ${topflag} + ${lowflag}` / 2 ) #标注5

else

echo “Error!”

fi

done

if [ “$thisnum” < “${arr_topnug[${lowflag}]}” -o “$thisnum” ==

“${arr_topnug[${lowflag}]}” ]

then

return 1

else

return 0

fi

fi

}#函数定义完毕

while read f

do

rg=“$(expr substr ${f} 1 10)” #标注6

checknum ${org}

returnval=$?

if [ “$returnval” == “1”]

then

echo “${f}” >>./Match_result.cdr#将匹配的记录存入结果文件1

else

echo “${f}” >>./NoMatch_result.cdr #将不匹配的记录存入结果文件2

fi

done < ./rttest.txt

echo “Time:$(date) ==>Proclearcase/” target=“_blank” >ccess is end! “

exit 0;

共2页: 1 [2] 下一页

原文转自:www.ltesting.net

篇2:一个Shell程序的性能优化Unix系统

MILY: ” times=“” new=“” roman?;=“” mso-fareast-font-family:=“” 宋体;=“” mso-font-kerning:=“” 1.0pt;=“” mso-ansi-language:=“” en-us;=“” mso-fareast-language:=“” zh-cn;=“” mso-bidi-language:=“” ar-sa?=“”>Shell是什么?

任何发明都具有供用户使用的界面,UNIX供用户使用的界面就是Shell(DOS的command熟悉吧,但UNIX的要强大的多),

Shell为用户提供了输入命令和参数并可得到命令执行结果的环境。

为了不同的需要,UNIX提供了不同的Shell。现在的UNIX大部分都支持BourneShell,以下教程就以BourneShell(Bsh)为例,一步步的领略UNIX Shell的强大功能,占先其强大魅力,达到更方便灵活的管理、应用UNIX的目的。

下载地址,见下:(不断更新中)

01.pdf

02.pdf

03.pdf

04.pdf

05.pdf

06.pdf

07.pdf

08.pdf

............不断上传中..........

篇3:一个Shell程序的性能优化Unix系统

Unix系统中性能优化以及确定系统中的性能瓶颈是系统管理员的主要任务之一。在一个计算机系统中, CPU、内存、硬盘和网络是影响系统性能的主要因素, 因此系统性能的监控以及调整也主要在于如何在这些资源中获得某种平衡, 以满足人们对系统性能的期望。

IBM小型机RS6000在企业应用中被广泛采用, 其上的AIX操作系统如同其它UNIX系统一样, 给系统管理员监控系统提供了非常丰富的手段。这里就以AIX系统中的几个监控工具为例, 利用shell程序及定时作业程序cron及强大的awk工具, 实现统计系统资源利用率, 可以每天统计内存的日均使用率、CPU的每日峰值、CPU的日均使用率, 并使每月统计量根据月中每日数据平均得出, 每月1号凌晨产生上月统计数据, 这样就可给系统管理员了解系统运行资源的率用率提供很好的参考。其中提到的系统工具Vmstat、svmon、awk等都很强大, 限于篇幅不作非常详细的介绍, 如想更透彻地了解这些命令的用法, 请参考有关技术资料或手册。

二、AIX中的性能监控工具

一个系统要为用户提供持续高可用性的服务, 不仅仅只要求它能够正常运行, 而且还要使其性能处于最佳状态。系统管理员的职责之一就是对系统进行性能统计分析, 掌握系统的运行状态和资源使用情况, 然后通过合理配置系统资源, 使系统健康运行。

从系统管理的角度看, 性能的管理主要集中在现有资源的分配利用上, 这些资源包括物理资源和逻辑资源。物理资源包括了CPU、内存、I/O设备, 逻辑设备包括逻辑卷管理器、虚拟内存管理器、系统资源控制器和文件系统等。这里重点介绍一些关于系统性能的命令和工具。

(一) iostat

iostat命令主要通过观察物理磁盘的活跃时间以及他们的平均传输速度, 监控系统输入/输出设备负载。根据iostat命令产生的报告, 用户可确定一个系统配置是否平衡, 并据此在物理磁盘与适配器之间更好地平衡输入/输出负载。

(二) netpmon

netpmon命令可以监控关于网络行为的系统事件和性能以及网络行为对CPU的消耗。netpmon命令在指定的监控周期报告网络行为。

(三) ps工具

ps命令是UNIX系统中最常见的命令, 它主要显示系统中关于进程的统计和状态信息, 如进程ID, I/O行为以及CPU利用率等。利用ps命令提供的信息, 可决定一个进程运行了多长时间, 进程使用了多少CPU时间, 以及进程是否受系统的惩罚。还可用ps命令确定进程使用了多少内存, 完成多少I/O, 进程的优先级以及是谁创建了进程。

(四) vmstat

vmstat命令报告关于核心线程, 虚拟内存, 自陷 (trap) , 磁盘以及CPU行为的统计。而且每种行为报告都被更细致地用百分比分别表示用户态、核态、空闲以及等待磁盘I/O等情况。

内核维持了对核心线程, 换页以及中断行为的统计数据, 而vmstat命令则通过使用knlist子程序和/dev/kmen伪设备驱动器访问这些数据。磁盘的输入/输出统计是通过设备驱动器维持的。对于磁盘, 平均传输速度是通过使用活跃时间核传输信息数目决定的。而活跃时间百分比则是从报告期间驱动器忙的时间量计算出来的。

(五) sar

sar命令报告CPU的使用情况, I/O以及其它系统行为。sar命令可以收集, 报告以及保存系统行为信息。如果没有指定输入文件, 则sar调用sarc命令访问系统数据。

用户可用让cron命令运行两个shell脚本 (/usr/lib/sa/sa1和/usr/lib/sa2) 以提供日统计和报表。在crontab文件/var/spool/cron/crontabs/adm中包括了一些样本节, 用于示范cron要在何时运行这些shell脚本。以这种方式收集到的数据对于确定系统的时间周期特征和决定峰值使用时间是很有用的。

但要注意的是, sar命令自己运行时会产生相当数量的读写。因此最好在没有工作量的情况下运行sar统计, 看看sar对总的统计数字有多大的影响。

(六) topas

topas命令用于监控各种系统资源, 如CPU的使用情况, CPU事件和队列, 内存和换页空间的使用, 磁盘性能, 网络性能以及NFS统计等。它还会报告指派给不同WLM类的进程对系统资源的消耗情况。它还能报告系统中最热门的进程和工作量管理器 (WLM) 的热门类。有关WLM类信息只有在WLM激活时才会显示。topas命令将热门进程定义为那些使用大量CPU时间的进程。topas命令没有作日志的选项, 所有信息都是实时的。

(七) truss

truss命令跟踪一个进程的系统调用、所接收的信号以及招致的机器错。要检查的应用程序可在truss命令的命令行中指定, 也可将truss命令挂在一个或多个已经在运行的进程上。

(八) svmon

svmon命令用于显示当前内存的状态。其可以捕捉和分析虚拟内存的快照信息, 所有的统计都是以4k内存页面为单位进行的。

三、系统利用率统计脚本程序

(一) 统计程序的简介

此系统利用率统计脚本程序由stat.sh、setup.sh组成, 仅在AIX 4.3.3与5.2环境中测试通过, 尚不支持其他UNIX服务器。推荐将两脚本置于/stat目录, 确保root对两文件具有执行权限 (cd/stat;chmod 755*.sh) 。可运行setup.sh脚本, 此脚本将直接在root的crontab中添加一项。每晚23:55执行stat.sh。脚本默认输出到/tmp/stat目录, result.lst为日均统计值, 输出格式为

“日期内存日均使用率%CPU每日峰值%CPU日均使用率%”

每月统计量根据月中每日数据平均得出, 每月1号凌晨产生上月统计数据并输出至report.lst。

脚本中关于crontab、awk的使用说明及shell编程的方法请查阅相关技术文档。

(二) setup.sh脚本

在系统的命令行中执行setup.sh, 将/stat/stat.sh添加到root用户的cron定时作业项中, 添加文件名为/var/spool/cron/crontabs/root。否则报出定时作业已经存在。代码如下:

(三) stat.sh脚本

此脚本使用AIX提供的两个重要系统性能工具vmstat和svmon分别收集cpu和内存的一整天的运行统计数据。为了不影响系统的运行, 设定为在定时作业cron中每60秒执行一次, 全天24小时运行, 并将数据保存到cpu.日期和mem.日期文件中, 以便于当天23:55分运行后使用awk工具进行一天的统计计算。

众所周知, awk进行文本处理是逐行处理的, 所以只需要设置计数器cnt变量进行累加以便于计算cpu和内存的平均利用率。我们以内存平均利用率的算法进行说明, 其他算法的产生与其相类似。

内存平均利用率的算法为:

设置cnt、delta、tbase、base变量初始为零, cnt为行计数变量, delta保存内存使用变化量, tbase为cron时间点上内存使用量, base为总内存量。

从mem.日期文件第一行开始, 如果base为0, 则将$2、$3域的值赋给base和tbase。然后进行cnt++下一行处理, 即将新时间点上的内存使用量减去上一时间点的内存使用量, 并将结果赋给delta变量自加:

直至最后一行, 进行100* (tbase+delta/cnt) /base即可得到当天的内存平均使用率了。

程序的源代码如下:

四、总结

综上所述, 在unix系统中, 提供了非常强大的系统监控工具。可利用这些工具并结合shell脚本的便利, 编制非常方便实用的监控程序, 并得到及时详细的系统性能统计信息。系统管理员可根据这些数据, 利用系统性能的调制工具, 例如f d p r、schedtune、vmtune等, 对系统的内核参数作出逻辑资源上的调整或者对硬件资源升级, 以此保障应用系统的安全稳定运行。

摘要:本文简要阐述了unix系统中 (主要以IBM的AIX为例) 进行系统性能管理的几种命令行工具, 并通过编写shell实例程序, 运用其中提到的工具实现系统资源利用率的统计程序, 为做好unix系统管理和调优提供参考。

篇4:一个Shell程序的性能优化Unix系统

关键词:IBM主机系统;移植;作业控制语言;初始化器

一、引言

IBM主机系统,又称IBM大型机,是20世纪60年代发展起来的计算机系统,在全世界各大国家中肩负着银行、保险、证券、通讯等行业的数据与信息处理工作,因为其独具的高安全性、高稳定性和强大的数据处理能力,迄今无可替代。

近几年来,主机系统的前景不断看好。从1994年起,IBM开始对大型机进行深入的技术改造,采用了新的CMOS技术,极大地缩小了大型机的系统体积,降低了能耗和散热成本,提高了性能价格比。另一方面,分布式计算开始变得庞杂起来,许多公司的管理费用激增,而且由于数据分散,在数据的互访和集中管理方面,安全和准确性都不够高,许多企业开始转向使用大型机。大型机在总体拥有成本上已经比分布计算廉价,制造业、保险、航空、运输及大型零售企业的大量事务处理对大型机的要求越来越高,这是大型机重新被人们认可的原因之一。

二、分布式与大型机

分布式计算在短期内给企业带来了高效,但随着时间的延续,企业系统扩大,数据分散存放在上百台服务器上,数据的查询成为问题,数据的互访和对大量数据的开采利用变得困难起来,一个新的趋势——再集中开始出现。如何将分布处理和集中计算结合起来,成为许多企业考虑的问题。大型机的系统完整性和大存储量的优势显示出来,开始承担用户再集中需求的任务。

在总体拥有成本上,随着时间的推移,小型机系统渐渐显现出极高的使用成本。或许人们在使用一年UNIX后,会说UNIX性价比高,但随着业务的增加,系统变得分散庞杂起来,维护费用增加。大型机挺过了关键的10年暗淡期,终于峰回路转。因此,越来越多的企业开始关注IBM主机系统,将自己的系统移植到主机系统上来。

三、移植平台间的差异

(一)主机操作系统Z/OS与UNIX

目前IBM主机的主流操作系统Z/OS是使用最广泛的基于64位Z体系结构大型机操作系统,它给在大型机上的应用程序员提供了稳定、安全和可持续运行的环境。

从本质上来说,UNIX是一个计算密集型的操作系统, CPU利用率较高,更适用于需要大量计算的环境;而主机操作系统Z/OS依赖于其强大的硬件后盾,除了强大的计算能力之外,更突出的是它强大的I/O处理能力,依托硬件上的FICON、ESCON等光纤通道,可同时应对大规模的并发用户,因此它是一个I/O密集型的操作系统。两种系统在很多内容上有着不同但又类似之处。

(二)进程与地址空间

在UNIX下,一个程序的执行通常称为一个进程,操作系统为每个进程分配一定的CPU、内存资源,使其运行,进程与进程之间可以通过信号量机制协同工作实现并发;而在Z/OS下没有进程的概念,与之对应的是地址空间(Address Space)的概念,任何用户的登录、程序的执行、作业的提交,系统都会为其生成一个地址空间。地址空间之间在批处理方式下一般没有通信,而通过联机交易处理方式实现程序间通信。在UNIX下通常会有守护进程(daemon)的概念,在主机环境中通常是一个长时间运行的作业的提交,可以从控制台为这个守护作业提供输入输出对象处理。

(三)文件的组织与编辑方式

从文件和数据格式上来说,UNIX系统是树状的目录结构,数据的组织以文件夹与文件的方式保存、管理;而在主机上,数据都保存在数据集里,数据集分顺序数据集、分区数据集与VSAM数据集,其组织方式没有多层树状结构,分区数据集下可包含称为member的顺序数据集,顺序数据集或VSAM数据集存储实际的数据。

数据的格式在UNIX下是面向字节,而在Z/OS下是面向记录的。数据的编辑在UNIX下通常是用VI,而在Z/OS下用的是ISPF编辑器。

(四)交互系统的区别

UNIX下用户登录并在Shell环境下执行Shell会话,可以通过发送远程登录rlogin命令或者远程登录telnet命令连接系统,一个用户可以同时打开多个用户会话。在主机环境下,用户通过TSO/E和它的菜单驱动接口ISPF登录系统,一个用户一次只能有一个活动的会话。

在UNIX系统中,用户可以通过后缀Shell命令观察处理进程和线程,可通过Kill命令结束一个任务。在主机环境中,用户通过作业处理子系统提供的SDSF查看他们提交作业的执行情况,并可以终止作业任务的执行。

四、移植实例

在原系统中有一个主控程序设计,主控程序是一个主调度程序,主要负责控制并发的进程数量及状态,系统支持的并发数量由主控程序的参数设置,通常设置为30。主控程序控制的每一个并发进程代表一个部门结息流程。假设一次性有1000个部门运行结息过程,主控程序负责调度,它轮寻所有进程,当一个进程结束时启动下一个进程,直到所有部门完成。

在Z/OS上没有进程的概念,针对这种后台批处理的结息方式,我们通过作业的方式实现,方案是为每个部门的结息准备一个JCL作业。所谓JCL(Job Control Language)是作业控制语言,通过它写一段作业脚本提交给系统,可以让系统执行相应的程序或进行相关的工作。为每个部门结息准备一个JCL作业,再准备一个主JCL作业,这个主JCL的任务就是去提交所有部门的JCL作业。

把结息过程定义为作业的好处是,在Z/OS里控制作业的并发数量以及作业调度的任务都可以由系统里的作业处理子系统JES2自动完成。在JES2里,有多个被称为Initiator的地址空间,每个Initiator都相当于UNIX下的一个守护进程,专门处理提交的作业。

Z/OS中的Intiator是一个自动调度和处理提交的多个作业的地址空间,它主要负责处理如下任务:

1. 确保同时运行的各项作业不会产生数据集使用上的冲突;

2.为作业分配必要的硬件设备,如磁带等;

3.从库中找到每个作业需要调用的可执行程序;

4.当一个作业运行完毕之后,在作业队列中清除该作业并要求处理下一个作业。

每个Initiator在同一时刻可以处理一个作业,而多个Intiator可以并发处理多个作业,各个Initiator并发处理各个作业都是在保证不出现死锁的前提下进行的。Initiator的数量可以在系统中设置,这样一来就自动实现了并发数的控制。比如我希望将并发数控制为50,我们在系统中设置50个Initiator,然后提交主JCL作业,主JCL作业再一次性提交1000个部门的作业,这些作业由JES自动调度给50个Initiator,并实现负载的均衡。

(一)Makefile的替代

在UNIX平台上,通常会在准备好源代码之后使用make工具进行编译,在执行make之前,需要一个命名为Makefile的特殊文件来告诉make需要做什么,该怎么做。通常make工具主要被用来进行工程编译和程序链接。

当使用make工具进行编译时,以下几种文件在执行make时将会被编译或重新编译:

1.所有的源文件没有被编译过,则对各个C源文件进行编译并进行链接,生成最后的可执行程序;

2.每一个在上次执行make之后修改过的C源代码文件在本次执行make时将会被重新编译;

3.头文件在上一次执行make之后被修改,则所有包含此头文件的C源文件在本次执行make时将会被重新编译。

Makefile文件是一个非常有效的文件,而在Z/OS平台中,没有类似的文件可用,通常的编译都是通过使用一个JCL作业去调用系统相关的针对编程语言的编译器去执行。

考虑到Makefile文件的对应参数、编译流程、依赖关系与JCL作业有很多相似点,我们的方案是还是使用JCL作业去编译程序,但将相关的源程序写在同一个JCL作业中。在Z/OS环境下一个JCL作业可以有多个作业步,每个作业步可以指定进行不同的操作或调用不同的程序,一个作业最多可以有255个作业步。因此,我们可以将相关联的源程序或者头文件放到同一个作业的不同作业步中,用于编译、链接,当有程序做了修改需要重新编译链接时,还是提交同一个编译作业就可完成。

(二)信号量机制的考虑

在实际结息流程中,通常每个进程都需要从数据库表里申请一个唯一的编号作为结息流程的流水号,最终保存到数据库。流水号是一个递增数列,无论进程执行是否成功,此流水号都必须唯一且不可让其他进程使用,即使进程执行失败,此流水号也必须作废而不可给后续进程使用。

在UNIX平台下,允许进程间通信,信号量机制就是用来解决进程同步与互斥问题的。通过P、V操作,保证并发进程互斥地访问数据库里的流水号资源。

而在Z/OS平台下,特别针对后台批处理方式下,用户的程序之间,作业与作业之间一般不允许相互通信,资源的互斥使用是通过Initiator调度实现的。

考虑到进程使用的流水号最终需要保存到数据库,而且流水号要求是递增数列,我们针对DB2数据库直接操作,DB2里面有个Sequence Object,它是一个递增数列,其递增幅度与初始值都可以在建立的时候设定。我们可以针对不同类型的流水号建立一个或多个Sequence Object,之后在任何需要用到流水号的地方,通过调用Sequence Object的next value取其当前值的下一个值,这样不管多少进程并发,在同一时刻其next value永远不可能重复,保证流水号的唯一性。

(三)程序的准备

移植初期首先需要将程序与数据导入到Z/OS环境下。

程序的导入可以通过FTP上传或3270终端直接上传的方式。首先需要在主机上针对不同属性的文件建立不同属性的数据集。由于主机上不是树状文件系统结构,所以要建立几个分区数据集,将相关文件保存成为相关数据集的member。如源文件可以建立一个数据集,名为userid.SRC,库文件可以建立为userid.LIB等,数据集的大小根据实际情况指定,我们的项目考虑可扩展性,建立的每个分区数据集以M为分配单位,初次分配量为300,再次分配量为100,目录空间大小为100。

将文件保存成文本格式上传,如果上传后都成了顺序数据集,可以写一个简单的JCL,使用IEBGENER将其拷贝到分区数据集里。

(四)数据的导入

对于数据库的导出导入,我们的方案是先将数据库创建脚本导入到数据集,使用主机上的SPUFI运行脚本创建好数据库、表空间和相关表、索引等。将原Infomix数据库的数据以文本方式导出,再导入到主机,最后导入到数据库。

在DB2里,数据库的导入有Import和Load两种方法。Import以SQL为基础,会写日志,可以对视图操作,表上定义的各种约束都将被检查,可以在目标表不存在的情况下通过ixf格式的文件创建表,不能在Import过程中搜集统计信息。Import成功后表就可以使用。

Load操作属于偏底层的操作,不写日志,不可以对视图操作,除了唯一性约束之外的各种约束都不在Load过程中被检查,不可以在目标表不存在的情况下创建表,可以在Load过程中搜集统计信息。Load过程成功后也有可能将表空间置于pending等的特殊状态,管理相对比较复杂。

总的来说,由于Load操作底层,因此速度很快,适合用于大量数据的导入;Import速度慢但管理简单,适用于少量数据导入。

由于我们的数据量非常大,因此选择使用Load导入数据。我们将导出的数据保存到主机的数据集里,通过写一个Load作业,从相关数据集导入需要的数据。在Load过程中,可能会因为参数或数据出错导致表空间置于reorganize pending状态,或者将某个表的Index置于rebuild pending状态,这时只需要将相应的表空间做一个REORG或者对相应的Index做一个rebuild就可以解决。

五、结束语

在决定对一套应用软件进行移植前,首先要明确移植的目的,选用适当的平台和语言,然后充分地分析移植前后软件运行环境的异同,决定要采取的技术和需要进行的结构调整,这样就可以系统而有序地完成大中型软件的移植工作,并可有效地提高软件质量,延长软件生命期。通过几个月的实践,我们的方案在可行性上得到了验证,作为实际的应用,还有很多地方有待我们进一步探讨。

篇5:一个Shell程序的性能优化Unix系统

bbs.chinaunix.net/forum/viewtopic.php?t=218853&show_type=new(+三问)

假如我需要在 command line 中⑦@些保留字元的功能P]的,就需要 quoting 理了,

在 bash 中,常用的 quoting 有如下三N方法:

* hard quote: (我),凡在 hard quote 中的所有 meta. 均被P]。

* soft quote: ” “ (p引),在 soft quoe 中大部份 meta. 都被P],但某些t保留(如 $ )。(]二)

* escape : (反斜),只有o接在 escape (跳字符)之後的我 meta. 才被P]。

( ]二:在 soft quote 中被豁免的具w meta. 清危我不完全知道,

有待大家a充,或透^作戆lF及理解。 )

篇6:一个Shell程序的性能优化Unix系统

%echo $

bcd

%echo $

cd

%echo $

abcd

%echo $

ab

%pos=1

%len=2

%echo $

bc

匹配正则表达式

代码:

# 打印匹配长度

%expr match $x “.”

1

%expr match $x “abc”

3

%expr match $x “bc”

0

字符串的掐头去尾

代码:

%x=aabbaarealwwvvww

%echo “$”

aabbaarealwwvv

%echo “$”

aabbaareal

%echo “$”

lwwvvww

%echo “$”

bbaarealwwvvww

其中 , # 表示掐头, 因为键盘上 # 在 $ 的左面,

shell中有关字符串的处理Unix系统

其中 , % 表示%, 因为键盘上 % 在 $ 的右面。

单个的表示最小匹配,双个表示最大匹配。

也就是说,当匹配的有多种方案的时候,选择匹配的最大长度还是最小长度。

字符串的替换

代码:

%x=abcdabcd

%echo $ # 只替换一个

bbcdabcd

%echo $ # 替换所有

bbcdbbcd

不可以使用 regexp , 只能用 * ? 的文件扩展方式。

篇7:一个Shell程序的性能优化Unix系统

shell版俄罗斯方块(转摘)

我所见的最强的shell

#!/bin/bash

# Tetris Game

# 10.21.2003 xhchen

#颜色定义

cRed=1

cGreen=2

cYellow=3

cBlue=4

cFuchsia=5

cCyan=6

cWhite=7

colorTable=($cRed $cGreen $cYellow $cBlue $cFuchsia $cCyan $cWhite)

#位置和大小

iLeft=3

iTop=2

((iTrayLeft = iLeft + 2))

((iTrayTop = iTop + 1))

((iTrayWidth = 10))

((iTrayHeight = 15))

#颜色设置

cBorder=$cGreen

cScore=$cFuchsia

cScoreValue=$cCyan

#控制信号

#改游戏使用两个进程,一个用于接收输入,一个用于游戏流程和显示界面;

#当前者接收到上下左右等按键时,通过向后者发送signal的方式通知后者,

sigRotate=25

sigLeft=26

sigRight=27

sigDown=28

sigAllDown=29

sigExit=30

#七中不同的方块的定义

#通过旋转,每种方块的显示的样式可能有几种

box0=(0 0 0 1 1 0 1 1)

box1=(0 2 1 2 2 2 3 2 1 0 1 1 1 2 1 3)

box2=(0 0 0 1 1 1 1 2 0 1 1 0 1 1 2 0)

box3=(0 1 0 2 1 0 1 1 0 0 1 0 1 1 2 1)

box4=(0 1 0 2 1 1 2 1 1 0 1 1 1 2 2 2 0 1 1 1 2 0 2 1 0 0 1 0 1 1 1 2)

box5=(0 1 1 1 2 1 2 2 1 0 1 1 1 2 2 0 0 0 0 1 1 1 2 1 0 2 1 0 1 1 1 2)

box6=(0 1 1 1 1 2 2 1 1 0 1 1 1 2 2 1 0 1 1 0 1 1 2 1 0 1 1 0 1 1 1 2)

#所有其中方块的定义都放到box变量中

box=($ $ $ $ $ $ $)

#各种方块旋转后可能的样式数目

countBox=(1 2 2 2 4 4 4)

#各种方块再box数组中的偏移

ffsetBox=(0 1 3 5 7 11 15)

#每提高一个速度级需要积累的分数

iScoreEachLevel=50  #be greater than 7

#运行时数据

sig=0    #接收到的signal

iScore=0  #总分

iLevel=0  #速度级

boxNew=()  #新下落的方块的位置定义

cBoxNew=0  #新下落的方块的颜色

iBoxNewType=0  #新下落的方块的种类

iBoxNewRotate=0  #新下落的方块的旋转角度

boxCur=()  #当前方块的位置定义

cBoxCur=0  #当前方块的颜色

iBoxCurType=0  #当前方块的种类

iBoxCurRotate=0  #当前方块的旋转角度

boxCurX=-1  #当前方块的x坐标位置

boxCurY=-1  #当前方块的y坐标位置

iMap=()    #背景方块图表

#初始化所有背景方块为-1, 表示没有方块

for ((i = 0; i < iTrayHeight * iTrayWidth; i++)); do iMap[$i]=-1; done

#接收输入的进程的主函数

function RunAsKeyReceiver()

{

local pidDisplayer key aKey sig cESC sTTY

pidDisplayer=

aKey=(0 0 0)

cESC=`echo -ne “”`

cSpace=`echo -ne “”`

#保存终端属性。在read -s读取终端键时,终端的属性会被暂时改变。

#如果在read -s时程序被不幸杀掉,可能会导致终端混乱,

#需要在程序退出时恢复终端属性。

sTTY=`stty -g`

#捕捉退出信号

trap “MyExit;” INT TERM

trap “MyExitNoSub;” $sigExit

#隐藏光标

echo -ne “[?25l”

while (( 1 ))

do

#读取输入。注-s不回显,-n读到一个字符立即返回

read -s -n 1 key

aKey[0]=$

aKey[1]=$

aKey[2]=$key

sig=0

#判断输入了何种键

if [[ $key == $cESC && $ == $cESC ]]

then

#ESC键

MyExit

elif [[ $ == $cESC && $ == “[” ]]

then

if [[ $key == “A” ]]; then sig=$sigRotate  #<向上键>

elif [[ $key == “B” ]]; then sig=$sigDown  #<向下键>

elif [[ $key == “D” ]]; then sig=$sigLeft  #<向左键>

elif [[ $key == “C” ]]; then sig=$sigRight  #<向右键>

fi

elif [[ $key == “W” || $key == “w” ]]; then sig=$sigRotate  #W, w

elif [[ $key == “S” || $key == “s” ]]; then sig=$sigDown  #S, s

elif [[ $key == “A” || $key == “a” ]]; then sig=$sigLeft  #A, a

elif [[ $key == “D” || $key == “d” ]]; then sig=$sigRight  #D, d

elif [[ “[$key]” == “[]” ]]; then sig=$sigAllDown  #空格键

elif [[ $key == “Q” || $key == “q” ]]      #Q, q

then

MyExit

fi

if [[ $sig != 0 ]]

then

#向另一进程发送消息

kill -$sig $pidDisplayer

fi

done

}

#退出前的恢复

function MyExitNoSub()

{

local y

#恢复终端属性

stty $sTTY

((y = iTop + iTrayHeight + 4))

#显示光标

echo -e “[?25h[$;0H”

exit

}

function MyExit()

{

#通知显示进程需要退出

kill -$sigExit $pidDisplayer

MyExitNoSub

}

#处理显示和游戏流程的主函数

function RunAsDisplayer()

{

local sigThis

InitDraw

#挂载各种信号的处理函数

trap “sig=$sigRotate;” $sigRotate

trap “sig=$sigLeft;” $sigLeft

trap “sig=$sigRight;” $sigRight

trap “sig=$sigDown;” $sigDown

trap “sig=$sigAllDown;” $sigAllDown

trap “ShowExit;” $sigExit

while (( 1 ))

do

#根据当前的速度级iLevel不同,设定相应的循环的次数

for ((i = 0; i < 21 - iLevel; i++))

do

sleep 0.02

sigThis=$sig

sig=0

#根据sig变量判断是否接受到相应的信号

if ((sigThis == sigRotate)); then BoxRotate;  #旋转

elif ((sigThis == sigLeft)); then BoxLeft;  #左移一列

elif ((sigThis == sigRight)); then BoxRight;  #右移一列

elif ((sigThis == sigDown)); then BoxDown;  #下落一行

elif ((sigThis == sigAllDown)); then BoxAllDown;  #下落到底

fi

done

#kill -$sigDown $$

BoxDown  #下落一行

done

}

#BoxMove(y, x),测试是否可以把移动中的方块移到(x, y)的位置, 返回0则可以, 1不可以

function BoxMove()

{

local j i x y xTest yTest

yTest=

xTest=

for ((j = 0; j < 8; j += 2))

do

((i = j + 1))

((y = $ + yTest))

((x = $ + xTest))

if (( y < 0 || y >= iTrayHeight || x < 0 || x >= iTrayWidth))

then

#撞到墙壁了

return 1

fi

if ((${iMap[y * iTrayWidth + x]} != -1 ))

then

#撞到其他已经存在的方块了

return 1

fi

done

return 0;

}

#将当前移动中的方块放到背景方块中去,

#并计算新的分数和速度级。(即一次方块落到底部)

function Box2Map()

{

local j i x y xp yp line

#将当前移动中的方块放到背景方块中去

for ((j = 0; j < 8; j += 2))

do

((i = j + 1))

((y = $ + boxCurY))

((x = $ + boxCurX))

((i = y * iTrayWidth + x))

iMap[$i]=$cBoxCur

done

#消去可被消去的行

line=0

for ((j = 0; j < iTrayWidth * iTrayHeight; j += iTrayWidth))

do

for ((i = j + iTrayWidth - 1; i >= j; i--))

do

if (($ == -1)); then break; fi

done

if ((i >= j)); then continue; fi

((line++))

for ((i = j - 1; i >= 0; i--))

do

((x = i + iTrayWidth))

iMap[$x]=$

done

for ((i = 0; i < iTrayWidth; i++))

do

iMap[$i]=-1

done

done

if ((line == 0)); then return; fi

#根据消去的行数line计算分数和速度级

((x = iLeft + iTrayWidth * 2 + 7))

((y = iTop + 11))

((iScore += line * 2 - 1))

#显示新的分数

echo -ne “[1m[3$m[$;$H$     ”

if ((iScore % iScoreEachLevel < line * 2 - 1))

then

if ((iLevel < 20))

then

((iLevel++))

((y = iTop + 14))

#显示新的速度级

echo -ne “[3$m[$;$H$    ”

fi

fi

echo -ne “[0m”

#重新显示背景方块

for ((y = 0; y < iTrayHeight; y++))

do

((yp = y + iTrayTop + 1))

((xp = iTrayLeft + 1))

((i = y * iTrayWidth))

echo -ne “[$;$H”

for ((x = 0; x < iTrayWidth; x++))

do

((j = i + x))

if (($ == -1))

then

echo -ne “ ”

else

echo -ne “[1m[7m[3$m[4$m[][0m”

fi

done

done

}

#下落一行

function BoxDown()

{

local y s

((y = boxCurY + 1))  #新的y坐标

if BoxMove $y $boxCurX  #测试是否可以下落一行

then

s=“`DrawCurBox 0`”  #将旧的方块抹去

((boxCurY = y))

s=“$s`DrawCurBox 1`”  #显示新的下落后方块

echo -ne $s

else

#走到这儿, 如果不能下落了

Box2Map    #将当前移动中的方块贴到背景方块中

RandomBox  #产生新的方块

fi

}

#左移一列

function BoxLeft()

{

local x s

((x = boxCurX - 1))

if BoxMove $boxCurY $x

then

s=`DrawCurBox 0`

((boxCurX = x))

s=$s`DrawCurBox 1`

echo -ne $s

fi

}

#右移一列

function BoxRight()

{

local x s

((x = boxCurX + 1))

if BoxMove $boxCurY $x

then

s=`DrawCurBox 0`

((boxCurX = x))

s=$s`DrawCurBox 1`

echo -ne $s

fi

}

#下落到底

function BoxAllDown()

{

local k j i x y iDown s

iDown=$iTrayHeight

#计算一共需要下落多少行

for ((j = 0; j < 8; j += 2))

do

((i = j + 1))

((y = $ + boxCurY))

((x = $ + boxCurX))

for ((k = y + 1; k < iTrayHeight; k++))

do

((i = k * iTrayWidth + x))

if (( $ != -1)); then break; fi

done

((k -= y + 1))

if (( $iDown > $k )); then iDown=$k; fi

done

s=`DrawCurBox 0`  #将旧的方块抹去

((boxCurY += iDown))

s=$s`DrawCurBox 1`  #显示新的下落后的方块

echo -ne $s

Box2Map    #将当前移动中的方块贴到背景方块中

RandomBox  #产生新的方块

}

#旋转方块

function BoxRotate()

{

local iCount iTestRotate boxTest j i s

iCount=$  #当前的方块经旋转可以产生的样式的数目

#计算旋转后的新的样式

((iTestRotate = iBoxCurRotate + 1))

if ((iTestRotate >= iCount))

then

((iTestRotate = 0))

fi

#更新到新的样式, 保存老的样式(但不显示)

for ((j = 0, i = ($ + $iTestRotate) * 8; j < 8; j++, i++))

do

boxTest[$j]=$

boxCur[$j]=$

done

if BoxMove $boxCurY $boxCurX  #测试旋转后是否有空间放的下

then

#抹去旧的方块

for ((j = 0; j < 8; j++))

do

boxCur[$j]=$

done

s=`DrawCurBox 0`

#画上新的方块

for ((j = 0, i = ($ + $iTestRotate) * 8; j < 8; j++, i++))

do

boxCur[$j]=$

done

s=$s`DrawCurBox 1`

echo -ne $s

iBoxCurRotate=$iTestRotate

else

#不能旋转,还是继续使用老的样式

for ((j = 0; j < 8; j++))

do

boxCur[$j]=$

done

fi

}

#DrawCurBox(bDraw), 绘制当前移动中的方块, bDraw为1, 画上, bDraw为0, 抹去方块,

function DrawCurBox()

{

local i j t bDraw sBox s

bDraw=

s=“”

if (( bDraw == 0 ))

then

sBox=“”

else

sBox=“[]”

s=$s“[1m[7m[3$m[4$m”

fi

for ((j = 0; j < 8; j += 2))

do

((i = iTrayTop + 1 + $ + boxCurY))

((t = iTrayLeft + 1 + 2 * (boxCurX + ${boxCur[$j + 1]})))

#[y;xH, 光标到(x, y)处

s=$s“[$;$H$”

done

s=$s“[0m”

echo -n $s

}

#更新新的方块

function RandomBox()

{

local i j t

#更新当前移动的方块

iBoxCurType=$

iBoxCurRotate=$

cBoxCur=$

for ((j = 0; j < $; j++))

do

boxCur[$j]=$

done

#显示当前移动的方块

if (( $ == 8 ))

then

#计算当前方块该从顶端哪一行“冒”出来

for ((j = 0, t = 4; j < 8; j += 2))

do

if (($ < t)); then t=$; fi

done

((boxCurY = -t))

for ((j = 1, i = -4, t = 20; j < 8; j += 2))

do

if (($ > i)); then i=$; fi

if (($ < t)); then t=$; fi

done

((boxCurX = (iTrayWidth - 1 - i - t) / 2))

#显示当前移动的方块

echo -ne `DrawCurBox 1`

#如果方块一出来就没处放,Game over!

if ! BoxMove $boxCurY $boxCurX

then

kill -$sigExit $

ShowExit

fi

fi

#清除右边预显示的方块

for ((j = 0; j < 4; j++))

do

((i = iTop + 1 + j))

((t = iLeft + 2 * iTrayWidth + 7))

echo -ne “[$;$H    ”

done

#随机产生新的方块

((iBoxNewType = RANDOM % $))

((iBoxNewRotate = RANDOM % $))

for ((j = 0, i = ($ + $iBoxNewRotate) * 8; j < 8; j++, i++))

do

boxNew[$j]=$;

done

((cBoxNew = ${colorTable[RANDOM % $]}))

#显示右边预显示的方块

echo -ne “[1m[7m[3$m[4$m”

for ((j = 0; j < 8; j += 2))

do

((i = iTop + 1 + $))

((t = iLeft + 2 * iTrayWidth + 7 + 2 * ${boxNew[$j + 1]}))

echo -ne “[$;$H[]”

done

echo -ne “[0m”

}

#初始绘制

function InitDraw()

{

clear

RandomBox  #随机产生方块,这时右边预显示窗口中有方快了

RandomBox  #再随机产生方块,右边预显示窗口中的方块被更新,原先的方块将开始下落

local i t1 t2 t3

#显示边框

echo -ne “[1m”

echo -ne “[3$m[4$m”

((t2 = iLeft + 1))

((t3 = iLeft + iTrayWidth * 2 + 3))

for ((i = 0; i < iTrayHeight; i++))

do

((t1 = i + iTop + 2))

echo -ne “[$;$H||”

echo -ne “[$;$H||”

done

((t2 = iTop + iTrayHeight + 2))

for ((i = 0; i < iTrayWidth + 2; i++))

do

((t1 = i * 2 + iLeft + 1))

echo -ne “[$;$H==”

echo -ne “[$;$H==”

done

echo -ne “[0m”

#显示“Score”和“Level”字样

echo -ne “[1m”

((t1 = iLeft + iTrayWidth * 2 + 7))

((t2 = iTop + 10))

echo -ne “[3$m[$;$HScore”

((t2 = iTop + 11))

echo -ne “[3$m[$;$H$”

((t2 = iTop + 13))

echo -ne “[3$m[$;$HLevel”

((t2 = iTop + 14))

echo -ne “[3$m[$;$H$”

echo -ne “[0m”

}

#退出时显示GameOVer!

function ShowExit()

{

local y

((y = iTrayHeight + iTrayTop + 3))

echo -e “[$;0HGameOver![0m”

exit

}

#游戏主程序在这儿开始.

if [[ != “--show” ]]

then

bash --show&  #以参数--show将本程序再运行一遍

RunAsKeyReceiver $!  #以上一行产生的进程的进程号作为参数

exit

else

#当发现具有参数--show时,运行显示函数

RunAsDisplayer

exit

fi

原文转自:www.ltesting.net

★ Shell常见知识(1)Unix系统

★ 摘怎么写

★ 转圈儿游戏作文

★ Makefile 简介(转的)Unix系统

★ 摘草莓作文怎么写

★ 美文佳句摘写

★ 经典哲理语句摘写

★ addol网吧游戏管理系统

★ 转档案 现实表现怎么写

篇8:一个Shell程序的性能优化Unix系统

1987年, 贝尔实验室的研究人员Jon Bentley在将他写于《Communication of the ACM》上的专栏《Programming Pearls》结集出版之际, 向广大读者及计算机专家下了一个有趣的战帖:

“写一个文字处理程序, 找出n个出现最频繁的单词, 并在输出结果的列表上加入它们出现的次数, 按照次数由大至小排序。”

著名计算机科学家Donald Knuth (中文名高德纳, 被誉为现代计算机科学鼻祖, 1974年图灵奖获得者, 《计算机程序设计艺术》作者, TeX及metafont的编制者) 与David Hanson分别回应了两个聪明有趣的程序, 每个程序都是花上数小时编写出来的。

鉴于Bentley最初的定义并不精准, 因而Hanson给这个问题增加了一个解释:

“在给定的文本文件以及整数n下, 必须将单词显示出来 (并且加上它们的出现频率) , 按照这些单词出现的频率, 从出现最多的n次, 依次往下排列”

令人称道的是, 针对这一问题, 贝尔实验室的研究人员Doug McIlroy回头检查了Knuth的程序后, 在Unix系统下仅花了几分钟就开发出一个只包含6行代码的脚本文件, 并能正确无误地解决Bentley的问题。这一短小精悍的脚本再次证明了Unix (其他linux、BSD等类Unix也一样) 系统在文本分析方面的强大能力与优异表现。

这个脚本的现代版本完整代码如下:

这一脚本完美体现了Unix的核心理念之一:大事化小。经由不断的任务细分, 最终将看似艰深的目标分解为触手可及的简单命令, 并且以Unix特有的“管道” (代码中的“|”) 将这些简单命令连接起来, 最终解决问题。

将此脚本存为一个wf (word frequency) 文件, 在类Unix系统 (例如笔者使用的Fedora 13) 下, 对莎士比亚名剧《哈姆雷特》试做分析可得到如下一些成果。范例中使用的《hamlet》文本下载于“古腾堡计划”网站。

1、出现最多的12个单词

结果大致和一般英语散文的预期相同。代码中的“pr–c4–t”意为使用pr命令重新格式化输出结果, 每行4列显示。

2、出现最少的12个单词 (部分, 许多次都仅出现一次)

其中的“99999”参数值没有任何特别意义, 仅是为了要一个很大的、确定超过单词计数的数字。tail命令从输出尾部提取文本。

二、修改wf文件用以分析中文文本文件

但是此脚本专为西方字母文字而设, 完全不能直接用来处理中文文本。因为此脚本中的第一句就会把非字母符号全都删除, 而中文恰是“非字母”符号。针对中文文本特殊性, 笔者对此脚本做了几处改造成为wfzh (word frequency for zh.cn) , 运用此脚本文件能有效地对中文文本进行字频分析。代码如下:

三、使用wfzh脚本工具分析对比二月河的《雍正皇帝》与《乾隆皇帝》中的前50个高频字

常识可知, 每一名作家都有自己的独特风格, 风格的体现之一, 就是某些字的使用频率。如果两部作品出于同一作家之手, 则这两部作品中的高频字以及高频字的排列顺序都应当非常接近。为验证这一说法, 笔者使用自己改编过的wfzh工具对著名作家二月河的两部巨著《雍正皇帝》与《乾隆皇帝》进行了对比分析, 分别列出两书中的前50个高频字, 分析结果如下 (为节省版面, 只显示前十个字, 全部的五十个字见后图) :

为清晰起见, 笔者使用freemind (一款思维导图软件) 对两个结果进行了连线分析, 具体结果见后文图一左:

由图可见, 二月河的用字风格在两书中基本一致, 常用的50个字, 甚至这50个字出现频率的排列顺序都相当一致。图一中加惊叹号的几个字是两书中独有的高频字, 这几个高频字在另一书中并非高频字, 但这理由也很容易找到。例如“雍正”之“正”字自然在《雍正皇帝》一书中出现频率远高于《乾隆皇帝》, “十”这个字则是因为《雍正皇帝》本就是描述多位皇子夺嫡之事, 其中十四阿哥等戏份甚重;同理, 《乾隆皇帝》一书中有一个“和”字出现的频率远高于《雍正皇帝》, 但那是因为《乾隆皇帝》中有一个重要人物:和珅。其余字都可按理解释。

倘若后世关于此两部小说出现了“是否为同一作者”的争论, 则此图或可成为一个支持“同作者说”的有力佐证。

四、运用分析《雍》与《乾》的同样方法分析《红楼梦》的前八十回与后四十回

作为一个业余红学爱好者, 笔者知道目前主流学者都认为《红楼梦》前八十回作者为曹雪芹, 后四十回为高鹗。但也有学者利用计算机字频分析得出了一百二十回作者为同一人的结论。鉴于此, 笔者试着使用自己改编的wfzh工具对《红楼梦》前八十回与后四十回文本进行了分析, 分析方法见前文所述。得出的结论见图二 (为对比起见, 将结果与《雍》《乾》图并列放置) :

从第十个字开始 (前十个字是语言学与统计学意义上的绝对高频字) , 前八十回作者与后四十回作者的用字风格开始出现明显分歧, 连线波动剧烈。另外, 前八十回的作者使用的几个高频字在后四十回中竟然不是高频字且无明显解释, 这几个字是“就、日、下、都、之”;同时, 后四十回作者也有几个惯用的高频字不见于前八十回高频字列表, 分别是“要、到、老、心、叫、爷”。

五、结论

根据书中自述, 《红楼梦》作者曾“披阅十载, 增删五次”, 那么同一作者前后写作风格 (至少用字风格) 出现重大改变的可能性并不大。可见, 得出前八十回与后四十回并非一个作者的结论。图二右更好的解释不如说是:高鹗虽竭力模仿曹雪芹的风格进行续作, 但仍然没能完全掩盖住自己的风格。遗憾的是, 目前没有高鹗所作的其它白话文学作品传世以资比照, 否则可以使这一课题的结论更加坚强。

参考文献

[1]《programming Pearls:A Literate Program》:A WEB program for common words, Comm ACM 29 (6) , 471-483, June (1986)

[2]Knuth的程序见《Literate Programming》, Published By Stanford University Center for the Study of Language and Information, 1992 ISBN 0-937073-80-6

上一篇:北河小学标准化小学自查评估报告下一篇:武汉防洪组织措施