发布新日志

  • [论坛] RUP和IPD流程的优缺点

    2008-03-25 13:50:45

    RUP的过程改进,倡导针对不同类型项目进行适当的裁剪,实际上这也是一种灵活适应的方式、随需而变的思想。我对此是理解并赞同的,但是我对RUP却一直保持一种相对谨慎的态度。

    对于RUP来说,首先,我认为它过于理想化和理论化,RUP 是过程组件、方法以及技术的框架,你可以将其应用于任何特定的软件项目,由用户自己限定 RUP 的使用范围。对于各种类型的软件项目,RUP并未给出具体的自身裁减及实施策略,总有些无依据可循的感觉。你既可以说它能解决任何问题,也可以说它什么都不是;其次,RUP从本质来说还是一个强调设计和规范的软件方法,从这个角度来讲,与传统的瀑布模型没有太大差别,它的灵活性较之敏捷方法还是相对较弱的。在一些小型软件项目、特别是不可预测的软件项目开发中,面临着各种紧急需求、面临着时间压力,沿用RUP是很难应付自如的。但是在另一方面,RUP强调对知识的收集、整理和加工定义,强调在软件开发的时候要有好的体系结构。所以它还是很有利于知识的积累和共享的。

    相比RUP ,敏捷方法如XP则更为灵活,倡导尽早的、持续的交付有价值的软件满足用户需要。用交流沟通取代详尽的文档,强调团队的主动、自律、自我组织和自发管理。而XP也是以代码为核心的一种方法,这里有很多的东西是未知的,知识只存在于两个地方:开发者的头脑和最后的代码。对于项目管理者来说,他们会认为敏捷开发方法弱化了知识管理的概念,而实际上敏捷开发注重的是最有价值的知识的积累和沉淀。

    如何灵活应对各种项目风险、如何最大化优先满足用户价值、又如何能够有效的控制项目开发过程、如果做好项目过程中的知识管理,是每一个软件项目管理者都需要深入思考的问题。RUP的倡导者一直强调RUP裁剪,实际上我认为RUP不仅仅是需要自身的裁剪,还需要学会融合。在RUP裁剪的同时,适宜的融合敏捷开发的各种实践。不要认为RUP与XP是矛盾的,其实不然,它们具有不同的原理、具有不同的应用领域。在 RUP 中融合了 XP 技术时,才会得到过程的正确量,既满足了项目所有成员的需要,又解决了所有主要的项目风险问题。对于一个工作于高信任环境中的小型项目团队,其中用户是团队的一部分,那么 XP 完全可以胜任。对于团队越来越分散,代码量越来越大,或者构架没有很好定义的情况,您需要做一些其他工作。在用户交互具有"契约"风格的项目中,仅有 XP 是不够的。RUP 是一个框架,可以从 RUP 出发,在必要时以一组更健壮的技术来扩展 XP。

    RUP最佳实践包括:

    1. 迭代开发: RUP的开发过程建立在一系列迭代之上,每次迭代都有一个固定的时间限制(例如四个星期),称为"时间盒",每次迭代结束的时候都发布一个稳定的小版本,该版本是最终系统的子集。"时间盒"是迭代开发中的关键概念:它意味着迭代周期的期限是固定的,如果目标没有完成,则放弃本次迭代的需求,而不是延长迭代的时间。

    2. 管理需求
    3. 使用基于组件的构架
    4. 可视建模
    5. 持续的质量验证
    6. 控制变更

    关于RUP阶段的一个简洁和准确的描述:

    1.初始-开发系统的业务用例;要求探索少量但是重要的需求(大约10%),以便获得范围、关键风险的尺度,并且决定是否进入细化阶段。

    2.细化-迭代地构建核心体系结构和解决技术风险。构建体系结构意味着真正的编程、集成及测试-这不是纸上谈兵或者丢弃原型。细化阶段,我们需要迭代地详细地探索大部分需求(大约80%),同时实现系统的核心风险部分。在整个细化阶段需求都可能是变化的,通过不断的"反馈-适应"循环,评估已实现的部分。

    可以看到,这与传统的瀑布风格的需求定义不同,其大部分需求是在开发核心体系结构的同时细化得到的,并且其从实际的开发中得到反馈。我们也能够以此为据来决定是否继续此项目。

    3.构造-迭代地构建细化阶段没有做的元素;迭代地集成和进行质量保证;准备部署。由于大部分需求的不稳定性已经在细化阶段澄清,所以在构造阶段需求的变化较少。

    4. 发布-完成&beta测试,确定版本,部署系统。RUP规则推荐"迭代周期的长度是2-6周"。 迭代开发和RUP的本质是采取小步骤,对于可能不完美的实现,迅速集成,质量保证,测试,及时获得反馈,然后根据反馈,调整需求、设计和实现。小步骤、反馈和调整是核心概念。

    迭代方法允许我们边学边走;随着迭代的进行,我们得到越来越多的真实的需求,更加客观的风险,以及完成该项目的更加准确的能力估计。简言之,经验使我们成为更好的计划者。

    12 个 XP 实践包括:

    有计划的开发:通过结合使用优先级"故事"和技术估算,确定下一版本的功能
    小版本:以小的增量版本经常向客户发布软件
    隐喻:隐喻是一个简单、共享的"故事"或描述,说明系统如何工作
    简单设计:通过保持代码简单从而保证设计简单。不断的在代码中寻找复杂点并且立刻进行移除
    测试驱动开发:用户编写测试内容以对"故事"进行测试。程序员编写测试内容来发现代码中的任何问题。在编写代码前先编写测试内容
    重构:这是一项简化技术,用来移除代码中的重复内容和复杂之处
    结对编程:团队中的两个成员使用同一台计算机开发所有的代码。一个人编写代码或者驱动,另一个人同时审查代码的正确性和可理解性
    集体代码所有权:任何人都拥有所有的代码。这就意味这每个人都可以在任何时候变更任何代码
    持续集成:每天多次创建和集成系统,只要任何实现任务完成就要进行
    每周 40 个小时:程序员在疲劳时无法保证最高效率。连续两周加班是绝对不允许的
    现场客户:一名真实的客户全时工作于开发环境中,帮助定义系统、编写测试内容并回答问题
    编码标准:程序员采用一致的编码标准证

    RUP与XP的融合,是各自特点的相互补充,也是软件开发方法的平衡之道。而对软件技术平衡的思考也可以说是技术成熟的开始吧。

    最后,再阐明我对软件项目开发的理解。在软件项目开发过程中,应该能够识别、分析不同软件项目的特点,采用相对适合的开发实践来适应软件开发过程,保证对软件开发的有效支持,以便能够创造出&ldquo足够好的&rdquo软件。而这个足够就是对进度、成本、质量之间的平衡,最大化满足客户需要的实现。
  • [论坛] CMMI 5能创造些什么 看富士通的软件过程改善历

    2008-02-28 10:06:21

    眼下,CMM似乎正褪去曾经笼照在它身上的神圣的光环。就连UML之父Ivar Jacobson博士游历中国之时,也不忘提醒他的中国同行:谨防掉入CMM陷阱。从这个角度看,富士通南大软件技术有限公司(FNST)正式通过软件行业内最高级别CMMI 5认证,似乎并不是一件值得关注的事情。但如果我们把历史翻回到二战刚刚结束之时的日本,我们一定会对这样一个事实表示惊异:二战结束初期,日本在工业基础极为低下的条件下,仅仅用了四年时间,就把曾是劣质产品代名词的日本产品,打造成了把美国同类产品打得在地上翻滚挣扎的生力军。造就这个奇迹的只有两个字——品质。

    因此,如果我们还原CMMI的本来面目,把它当作是提高品质的有力手段时,FNST的CMMI 5认证之路就有理由值得我们关注了。而如果我们进一步反思日后这场竞争中美国产品重机关报崛起的原因,就不难发现美国绝地反击的法宝——态度。美国人不仅重新认识了造就日本产品奇迹的戴明博士,而且将品质管理上升到了经营管理的最高层次。基于对这种态度所起的作用的认识,我们就更应该下番功夫去研究一下FNST的CMMI 5认证之路了。

    品质无泪

    提起富士通公司,中国国内几乎到了无人不晓的地步,但提起它的软件业务,却没有几个人能说得清,通过富士通南大软件技术有限公司总经理北冈正治的介绍,我们了解到这源于富士通公司在中国国内的分公司众多。

    北冈先生介绍说:“富士通是全球第三大IT及服务公司、全球前五大服务器和PC机生产商、世界第二大企业用硬盘驱动器的制造商和第四大移动硬盘制造商。三十年来,富士通在中国共设立了38家公司;其中,富士通直接投资的与软件开发相关的公司就有四家。FNST是唯一一家面向服务器基础软件的研发机构,主要业务涉及Linux服务器平台、服务器中间件、服务器硬件验证、嵌入式软件和系统应用软件。”从这简单的几句话中我们不难看出南大富士通公司的技术开发难度有多高。无论是围绕服务器平台的整体的软件开发,还是底层的硬件测试与验证,再到存储/网络/CPU的管理与服务器中间件和应用系统,所涉及的技术都非常基础。由此我们也不难想见,在这样一家需要建立高水平的开发团队才能应对的软件企业实施CMMI,确实不是一件容易的事情。

    谈起选择CMMI的原因,FNSTCMMI过程改善委员会执行主席蔡志旻先生这样介绍道:“与CMMI类似的模型还有很多,而FNST之所以最终选择了CMM/CMMI模型,是站在提高软件开发品质、成为一流软件企业、提高顾客满意度的角度上综合考虑的。”

    事实上,FNST自1999年成立之初就导入了富士通为了提高软件产品的开发能力和产品质量,日本富士通株式会社长期积累而形成的一套行之有效的方法和技术使得FNST是在一个高标准的基础上实施CMM认证的。从2002年下半年开始导入CMM模型进行品质改善和过程改善,一年以后FNST就通过了“软件过程成熟度(CMM3级)论证”,并获得证书。

    FNST取得了一个良好的开端,这意味着已经取得了成功的一半。这个良好开端还表现在FNST在CMM认证之初,就采取了一些正确的做法。

    CMM/CMMI模型只是给出了为了进行过程改善,"要做什么",而需要组织把抽象的CMMI概念和目标具体化。在这个过程中,FNST没有让过于偏向理论论述的国内咨询公司参与进来,而是自己选择了“What to Do(CMMI书籍)=》Why to Do(软件工程典籍)=》How to Do(建立公司规范)=》Do it!”这样一条改进之路。真正做到让开发人员理解蕴涵再CMMI相关PA(Practice Area)规定之后的软件工业界三十年来的经验之精髓然后再在实际工作中运用这些经验方法。

    要达到品质无泪的境界,全员参与是必不可少的一个环节。值得一提的是,富士通是一家有着追求优异品质传统的公司。富士通品质保证本部长木村弘正这样介绍说:“出于让各分公司都要按照同样优秀的标准提供高品质产品的需求,富士通公司很早就成立了品质保证部。富士通公司内部有一个共识,这就是一个细节上的小失误,也会带来很大的问题。富士通公司的产品线很长,涵盖了软、硬件的各个方面,在软件开发过程中,确实不存在能完美解决所有问题的银弹,但从上而下的帮助可以让各个公共司都按照正确的流程来办事,而细节则由他们自己把握。”就细节问题,FNST技术管理课SQA(品质保证)主任王毅峰介绍说:“FNST实施过程改善,是应开发人员之需,而并非是管理层单方面的意志决定一切的。这避免了常见的过程改善误区:规范的制订者并不是规范的实际执行者;开发者无法从过程改善中受益。”

    尽管有了一个好的开端,但FNST的高层领导并不敢松懈,2003年的顾客满意度调查数据表明,2003年8月的顾客满意度得分在满分100分的条件下,FNST的得分只有43.02。蔡志旻先生对这个成绩做了注解:“这表明用户用不用你的产品要依他们的心情而定,还远没有达到离不开你的境界。”

    合于术数

    中国人爱把成功的步骤归纳为修身、齐家、治国、平天下,而修身的要旨则可归纳为“法于阴阳,合于术数”,这种思想恰好也和CMMI 4级认证的定量管理不谋而合。在从已定义的三级向已管理的四级的转化过程中,对软件开发实施定量管理,对于整个世界软件业界而言都是个具有挑战性的课题,原因就在于软件开发的不可重复性。但对FNST,这却又是一个必须要迈过去的坎。

    对这个问题,蔡志旻先生道出了其中的秘密:“与传统制造业相比,软件开发的定量数据的精确性要低很多。其次,数据的收集是件极其耗费时间的工作,而且容易出错。最后,软件开发的数据不能用于评判开发人员的工作。针对这三个难题,我们开发了SPIF(Software Process Integrated Framework)可视化项目管理辅助平台,实现数据的一次录入和处处使用,抓住品质,规模和生产率,日程三个对象实施定量管理,明确定量管理的意义,明确数据判断和分析的方法,特别是如何根据数据来把握开发状况,运用数据来调整下一步的开发活动。”

    2004年12月,FNST通过了CMM4级认证,成为南京地区首家通过此认证的软件企业。难能可贵的是,FNST此时并没有把自己的经验作为独门武功珍藏起来,而是利用SPIF工具去帮助其他软件企业。包括江苏金智软件、苏州方舟公司等国内公司,都曾受益于SPIF工具及FNST积累的经验,并与移软公司,金鹰公司,趋势公司等进行了广泛的交流。而此时FNST的客户满意度得分也已提高到了60.60。然而,此时的FNST的业务百分之百地来自于富士通集团本部,面对来自印度等地区关联公司的竞争,FNST并没有让提高品质的工作就此止步。

    问题背后的问题

    富士通公司在给一家欧洲大型航空公司的订票呼叫中心实施IT整体解决方案时,富士通支持人员发现新业务流程实施之后,呼叫中心接到了很多的电话投诉。富士通支持人员并没有通过“简单地培训服务中心接待人员技能、增加接待人员数量”等表面措施来缓解这个现象,而是通过将电话投诉的内容进行详细的分类和分析,发现大多数投诉的内容集中在“电子机票无法打印”的问题上。再深入分析下去,了解到问题的根源在于印刷票据的打印机出现故障。于是在富士通支持人员的建议下更换了打印设备,大幅度地提高了机票打印的可靠性和效率。在很短的时间内,就使服务中心同期内接到的电话投诉量下降了80%。

    对此案例,CMMI过程改善委员会成员王晶先生介绍,当某件事情的执行过程中出现问题的时候,如果只是简单的“头痛医头、脚痛医脚”,采取治标不治本的措施来消除问题的表象,那么会出现类似问题的隐患仍然可能在将来爆发。在问题发生时,为了采取改善措施来消除问题产生的根源以避免今后同样发生,我们必须连问几个“为什么”,以找到导致问题出现的根本原因并消除它,即解决“问题背后的问题”。这种方法称之为“根本原因分析法。”

    在FNST,根本原因分析法甚至从2002年就开始在各个项目组得到应用。在面向CMM 4尤其是面向CMMI 5的改善活动,FNST重点在解决“处理交货后产生的质量缺陷”以及“分析客户满意度调查反馈的客户最不满点”的问题上,充分地使用了“根本原因分析法”,在找到问题的根本原因所在后,将改善方法应用到在后续开发环节中,尽可能提前监测到类似缺陷来避免问题的再次发生。较大程度地改善了产品的品质,提高了顾客满意度评价

    2006年4月13日,FNST正式通过了CMMI Level 5的审查,成为江苏省内注册的首家通过该级别认证的的外资企业。而此时的顾客满意度得分,也预计将在2005年4月的72.67分的基础上提高于80分。另一个指标更明显地反映出了CMMI给FNST带来的变化:以PGRelief产品为例,在与FNST成立不久的2000年,产品交付后每千行程序的缺陷率相比,2003年通过CMM3时下降为92%,2004年通过CMM4后下降为35%,到实施CMMI5的2005年底则下降为2000年缺陷率的9%。软件产品不能按照交付的现象也已得到了根本杜绝。

    快乐工作,共享成长

    按照挖掘“问题背后的问题”这一思路去分析,问题也就不可能不出现。蔡志旻先生显然认同这一观点,他说:“通过了CMMI 5并不是公司提高品质的终点,FNST的新目标是在原先“人人参与,日日改善”的基础上,提出了“快乐工作,共享成长”的新口号,在2009年公司成立十周年之际,成为世界一流的软件开发公司。以产品交付后缺陷率这一指标来说,我们要达到富士通本部的世界先进水平。”

    在采访过程中,北冈先生经常需要闭目休息一会儿,由此可见喜欢在业余时间练二胡的他为提高品质的活动付出了多大的心力,再看到蔡志旻、王晶、王毅峰等人匆忙的背影,我们不难想见FNST把品质摆在了一个什么样的地位上。然而,现在非常多的CEO在品质和利润发生冲突时,会毫不迟疑地选择后者。关于这二者的差异,被誉为是“美国最著名的质量管理家”的克劳士比曾做过这样的注解:未来10年,将有更多的产品及公司会因缺乏质量管理而不是因财源短缺而彻底失败。那些醒得早的人,即可掌握市场;那些迟疑过久的人,只能为人作嫁家。克劳士比的话同样道出了CMMI5的真正价值所在,也许我们这个时候更想看到CMMI5在接下来的时间里,为富士通南大软件技术有限公司创造的价值究竟会达到一个什么样的数字。
  • [论坛] HTTP错误大全

    2008-01-17 10:23:39

    HTTP错误大全
    HTTP 400 - 请求无效
    HTTP 401.1 - 未授权:登录失败
    HTTP 401.2 - 未授权:服务器配置问题导致登录失败
    HTTP 401.3 - ACL 禁止访问资源
    HTTP 401.4 - 未授权:授权被筛选器拒绝
    HTTP 401.5 - 未授权:ISAPI 或 CGI 授权失败

    HTTP 403 - 禁止访问
    HTTP 403 - 对 Internet 服务管理器 的访问仅限于 Localhost
    HTTP 403.1 禁止访问:禁止可执行访问
    HTTP 403.2 - 禁止访问:禁止读访问
    HTTP 403.3 - 禁止访问:禁止写访问
    HTTP 403.4 - 禁止访问:要求 SSL
    HTTP 403.5 - 禁止访问:要求 SSL 128
    HTTP 403.6 - 禁止访问:IP 地址被拒绝
    HTTP 403.7 - 禁止访问:要求客户证书
    HTTP 403.8 - 禁止访问:禁止站点访问
    HTTP 403.9 - 禁止访问:连接的用户过多
    HTTP 403.10 - 禁止访问:配置无效
    HTTP 403.11 - 禁止访问:密码更改
    HTTP 403.12 - 禁止访问:映射器拒绝访问
    HTTP 403.13 - 禁止访问:客户证书已被吊销
    HTTP 403.15 - 禁止访问:客户访问许可过多
    HTTP 403.16 - 禁止访问:客户证书不可信或者无效
    HTTP 403.17 - 禁止访问:客户证书已经到期或者尚未生效 HTTP 404.1 -

    无法找到 Web 站点
    HTTP 404- 无法找到文件
    HTTP 405 - 资源被禁止
    HTTP 406 - 无法接受
    HTTP 407 - 要求代理身份验证
    HTTP 410 - 永远不可用
    HTTP 412 - 先决条件失败
    HTTP 414 - 请求 - URI 太长
    HTTP 500 - 内部服务器错误
    HTTP 500.100 - 内部服务器错误 - ASP 错误
    HTTP 500-11 服务器关闭
    HTTP 500-12 应用程序重新启动
    HTTP 500-13 - 服务器太忙
    HTTP 500-14 - 应用程序无效
    HTTP 500-15 - 不允许请求 global.asa
    Error 501 - 未实现
    HTTP 502 - 网关错误
    用户试图通过 HTTP 或文件传输协议 (FTP) 访问一台正在运行 Internet 信息服务 (IIS) 的服务器上的内容时,IIS 返回一个表示该请求的状态的数字代码。该状态代码记录在  
    IIS 日志中,同时也可能在 Web 浏览器或 FTP 客户端显示。状态代码可以指明具体请求是否已成功,还可以揭示请求失败的确切原因。
    日志文件的位置
    在默认状态下,IIS 把它的日志文件放在 %WINDIRSystem32Logfiles 文件夹中。每个万维网 (WWW) 站点和 FTP 站点在该目录下都有一个单独的目录。在默认状态下,每天都会在
    这些目录下创建日志文件,并用日期给日志文件命名(例如,exYYMMDD.log)。
    HTTP
    1xx - 信息提示

    这些状态代码表示临时的响应。客户端在收到常规响应之前,应准备接收一个或多个 1xx 响应。 • 100 - 继续。
    • 101 - 切换协议。
    2xx - 成功

    这类状态代码表明服务器成功地接受了客户端请求。 • 200 - 确定。客户端请求已成功。
    • 201 - 已创建。
    • 202 - 已接受。
    • 203 - 非权威性信息。
    • 204 - 无内容。
    • 205 - 重置内容。
    • 206 - 部分内容。
    3xx - 重定向

    客户端浏览器必须采取更多操作来实现请求。例如,浏览器可能不得不请求服务器上的不同的页面,或通过代理服务器重复该请求。 • 302 - 对象已移动。
    • 304 - 未修改。
    • 307 - 临时重定向。
    4xx - 客户端错误

    发生错误,客户端似乎有问题。例如,客户端请求不存在的页面,客户端未提供有效的身份验证信息。 • 400 - 错误的请求。
    • 401 - 访问被拒绝。IIS 定义了许多不同的 401 错误,它们指明更为具体的错误原因。这些具体的错误代码在浏览器中显示,但不在 IIS 日志中显示: • 401.1 - 登录失败。
    • 401.2 - 服务器配置导致登录失败。
    • 401.3 - 由于 ACL 对资源的限制而未获得授权。
    • 401.4 - 筛选器授权失败。
    • 401.5 - ISAPI/CGI 应用程序授权失败。
    • 401.7 – 访问被 Web 服务器上的 URL 授权策略拒绝。这个错误代码为 IIS 6.0 所专用。

    • 403 - 禁止访问:IIS 定义了许多不同的 403 错误,它们指明更为具体的错误原因: • 403.1 - 执行访问被禁止。
    • 403.2 - 读访问被禁止。
    • 403.3 - 写访问被禁止。
    • 403.4 - 要求 SSL。
    • 403.5 - 要求 SSL 128。
    • 403.6 - IP 地址被拒绝。
    • 403.7 - 要求客户端证书。
    • 403.8 - 站点访问被拒绝。
    • 403.9 - 用户数过多。
    • 403.10 - 配置无效。
    • 403.11 - 密码更改。
    • 403.12 - 拒绝访问映射表。
    • 403.13 - 客户端证书被吊销。
    • 403.14 - 拒绝目录列表。
    • 403.15 - 超出客户端访问许可。
    • 403.16 - 客户端证书不受信任或无效。
    • 403.17 - 客户端证书已过期或尚未生效。
    • 403.18 - 在当前的应用程序池中不能执行所请求的 URL。这个错误代码为 IIS 6.0 所专用。
    • 403.19 - 不能为这个应用程序池中的客户端执行 CGI。这个错误代码为 IIS 6.0 所专用。
    • 403.20 - Passport 登录失败。这个错误代码为 IIS 6.0 所专用。

    • 404 - 未找到。 • 404.0 -(无) – 没有找到文件或目录。
    • 404.1 - 无法在所请求的端口上访问 Web 站点。
    • 404.2 - Web 服务扩展锁定策略阻止本请求。
    • 404.3 - MIME 映射策略阻止本请求。

    • 405 - 用来访问本页面的 HTTP 谓词不被允许(方法不被允许)
    • 406 - 客户端浏览器不接受所请求页面的 MIME 类型。
    • 407 - 要求进行代理身份验证。
    • 412 - 前提条件失败。
    • 413 – 请求实体太大。
    • 414 - 请求 URI 太长。
    • 415 – 不支持的媒体类型。
    • 416 – 所请求的范围无法满足。
    • 417 – 执行失败。
    • 423 – 锁定的错误。
    5xx - 服务器错误

    服务器由于遇到错误而不能完成该请求。 • 500 - 内部服务器错误。 • 500.12 - 应用程序正忙于在 Web 服务器上重新启动。
    • 500.13 - Web 服务器太忙。
    • 500.15 - 不允许直接请求 Global.asa。
    • 500.16 – UNC 授权凭据不正确。这个错误代码为 IIS 6.0 所专用。
    • 500.18 – URL 授权存储不能打开。这个错误代码为 IIS 6.0 所专用。
    • 500.100 - 内部 ASP 错误。

    • 501 - 页眉值指定了未实现的配置。
    • 502 - Web 服务器用作网关或代理服务器时收到了无效响应。 • 502.1 - CGI 应用程序超时。
    • 502.2 - CGI 应用程序出错。application.

    • 503 - 服务不可用。这个错误代码为 IIS 6.0 所专用。
    • 504 - 网关超时。
    • 505 - HTTP 版本不受支持。

    常见的 HTTP 状态代码及其原因
    • 200 - 成功。 此状态代码表示 IIS 已成功处理请求。
    • 304 - 未修改。 客户端请求的文档已在其缓存中,文档自缓存以来尚未被修改过。客户端使用文档的缓存副本,而不从服务器下载文档。
    • 401.1 - 登录失败。 登录尝试不成功,可能因为用户名或密码无效。
    • 401.3 - 由于 ACL 对资源的限制而未获得授权。 这表示存在 NTFS 权限问题。即使您对试图访问的文件具备相应的权限,也可能发生此错误。例如,如果 IUSR 帐户无权访问  
    C:WinntSystem32Inetsrv 目录,您会看到这个错误。 有关如何解决此问题的其他信息,请单击下面的文章编号,查看 Microsoft 知识库中相应的文章:
    187506 INFO: IIS 4.0 的基础 NTFS 权限
    • 403.1 - 执行访问被禁止。 下面是导致此错误信息的两个常见原因: • 您没有足够的执行许可。例如,如果试图访问的 ASP 页所在的目录权限设为“无”,或者,试图执行的  
    CGI 脚本所在的目录权限为“只允许脚本”,将出现此错误信息。若要修改执行权限,请在 Microsoft 管理控制台 (MMC) 中右击目录,然后依次单击属性和目录选项卡,确保为
    试图访问的内容设置适当的执行权限。
    • 您没有将试图执行的文件类型的脚本映射设置为识别所使用的谓词(例如,GET 或 POST)。若要验证这一点,请在 MMC 中右击目录,依次单击属性、目录选项卡和配置,然后
    验证相应文件类型的脚本映射是否设置为允许所使用的谓词。

    • 403.2 - 读访问被禁止。验证是否已将 IIS 设置为允许对目录进行读访问。另外,如果您正在使用默认文件,请验证该文件是否存在。 有关如何解决此问题的其他信息,请单
    击下面的文章编号,查看 Microsoft 知识库中相应的文章:
    247677 错误信息:403.2 Forbidden:Read Access Forbidden(403.2 禁止访问:读访问被禁止)
    • 403.3 - 写访问被禁止。 验证 IIS 权限和 NTFS 权限是否已设置以便向该目录授予写访问权。有关如何解决此问题的其他信息,请单击下面的文章编号,查看 Microsoft 知识
    库中相应的文章:
    248072 错误信息:403.3 Forbidden:Write Access Forbidden(403.3 禁止访问:写访问被禁止)
    • 403.4 - 要求 SSL。禁用要求安全通道选项,或使用 HTTPS 代替 HTTP 来访问该页面。如果没有安装证书的 Web 站点出现此错误,请单击下面的文章编号,查看 Microsoft 知
    识库中相应的文章:
    224389 错误信息:HTTP 错误 403、403.4、403.5 禁止访问:要求 SSL
    • 403.5 - 要求 SSL 128。禁用要求 128 位加密选项,或使用支持 128 位加密的浏览器以查看该页面。如果没有安装证书的 Web 站点出现此错误,请单击下面的文章编号,查看  
    Microsoft 知识库中相应的文章:
    224389 错误信息:HTTP 错误 403、403.4、403.5 禁止访问:要求 SSL
    • 403.6 - IP 地址被拒绝。您已把您的服务器配置为拒绝访问您目前的 IP 地址。 有关如何解决此问题的其他信息,请单击下面的文章编号,查看 Microsoft 知识库中相应的文
    章:
    248043 错误信息:403.6 - Forbidden:IP Address Rejected(403.6 - 不可用:IP 地址被拒绝)
    • 403.7 - 要求客户端证书。您已把您的服务器配置为要求客户端身份验证证书,但您未安装有效的客户端证书。 有关其他信息,请单击下面的文章编号,查看 Microsoft 知识
    库中相应的文章:
    190004 错误 403.7 或“Connection to Server Could Not Be Established”(无法建立与服务器的连接)
    186812 PRB:错误信息:403.7 Forbidden:Client Certificate Required(403.7 禁止访问:要求客户端证书)
    • 403.8 - 站点访问被拒绝。您已为您用来访问服务器的域设置了域名限制。有关如何解决此问题的其他信息,请单击下面的文章编号,查看 Microsoft 知识库中相应的文章:
    248032 错误信息:Forbidden:Site Access Denied 403.8(禁止访问:站点访问被拒绝 403.8)
    • 403.9 - 用户数过多。与该服务器连接的用户数量超过了您设置的连接限制。 有关如何更改此限制的其他信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文
    章:
    248074 错误信息:Access Forbidden:Too Many Users Are Connected 403.9(禁止访问:连接的用户太多 403.9)
    注意:Microsoft Windows 2000 Professional 和 Microsoft Windows XP Professional 自动设置了在 IIS 上最多 10 个连接的限制。您无法更改此限制。
    • 403.12 - 拒绝访问映射表。 您要访问的页面要求提供客户端证书,但映射到您的客户端证书的用户 ID 已被拒绝访问该文件。 有关其他信息,请单击下面的文章编号,以查看  
    Microsoft 知识库中相应的文章:
    248075 错误信息:HTTP 403.12 - Access Forbidden:Mapper Denied Access(HTTP 403.12 - 禁止访问:映射表拒绝访问)
    • 404 - 未找到。 发生此错误的原因是您试图访问的文件已被移走或删除。如果在安装 URLScan 工具之后,试图访问带有有限扩展名的文件,也会发生此错误。这种情况下,该
    请求的日志文件项中将出现“Rejected by URLScan”的字样。
    • 500 - 内部服务器错误。 很多服务器端的错误都可能导致该错误信息。事件查看器日志包含更详细的错误原因。此外,您可以禁用友好 HTTP 错误信息以便收到详细的错误说明
    。 有关如何禁用友好 HTTP 错误信息的其他信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:
    294807 如何在服务器端禁用 Internet Explorer 5 的“显示友好 HTTP 错误信息”功能
    • 500.12 - 应用程序正在重新启动。 这表示您在 IIS 重新启动应用程序的过程中试图加载 ASP 页。刷新页面后,此信息即会消失。如果刷新页面后,此信息再次出现,可能是
    防病毒软件正在扫描 Global.asa 文件。 有关其他信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:
    248013 错误信息:HTTP Error 500-12 Application Restarting(HTTP 错误 500-12 应用程序正在重新启动)
    • 500-100.ASP - ASP 错误。 如果试图加载的 ASP 页中含有错误代码,将出现此错误信息。若要获得更确切的错误信息,请禁用友好 HTTP 错误信息。默认情况下,只会在默认  
    Web 站点上启用此错误信息。有关如何在非默认的 Web 站点上看到此错误信息的其他信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:
    261200 显示 HTTP 500 错误信息,而不显示 500-100.asp 的 ASP 错误信息
    • 502 - 网关错误。 如果试图运行的 CGI 脚本不返回有效的 HTTP 标头集,将出现此错误信息。

    HTTP错误大全.doc
    (2008-01-17 10:22:39, Size: 49 kB, Downloads: 0)

  • 告诉你真实的韩国及对华情结!

    2007-11-17 11:17:25

    近年来,韩流滚滚,中国不少媒体也不客观报道,把韩国描绘成为一个继承儒家传统最好的国度,韩国人如何有血性、如何爱国,韩国是如何的俊男美女,恨不得拜倒在韩国的石榴裙下。国内韩流日盛,国内媒体对韩国的报道也非常多,当然几乎都是充满赞颂之词,再加上精美的韩国影视歌曲的轮番轰炸,这让大多数不了解韩国的中国人对韩国产生了相当的好感。

    但真正的韩国如何呢?与韩流相对,最近网上出现了不少揭露“真实”韩国的文章,可惜有的年代久远,有些又非常极端,充满个人感情,但他们大部分内容在我看来是比较真实的。我本不想挑起与邻国的矛盾,但国内媒体对韩国的过分吹捧和韩国媒体对中国的极端歪曲实在形成了太鲜明的反差,让我有点看不过去,所以这里结合我和所认识的朋友们在韩国的经历来谈谈我眼中的韩国,希望能去伪存真。文章比较长,请耐心看,然后明眼的看官自行判断。

    1. 韩国从建国起对中国的侮辱史
    50年转眼一挥间,1945年日本败亡,朝鲜终于又迎来了独立。可惜南北在不同势力的支持下不能统一成立政府。50年代朝鲜战争爆发,38线成了天堑沟壑,中国自然在韩国人眼中成了十恶不赦,阻止“大韩民族”统一的罪魁祸首(在此引用韩国人原话)。
        
      韩国政府成立之后,接连颁发排斥华商的禁令,包括“仓库封锁令”、“外币使用规模限制令”等等,这便是华商受难的开始。接着,自由党和朴正熙政权两次进行“货币改革”,偏爱现金的华商更受到致命性打击,很多华商因此变得一贫如洗。1961年,韩国政府颁布“外国人拥有土地禁止法”,1971年制定“外国人土地取得及其管理法”,规定华人一家只能拥有一间房屋、一家商店,连炸酱面售价也受到严格管制的情况下,华商便成了走投无路的一群。70年代初,原本有12万人口的华商锐减到只剩下2万人。唐人街遍布世界各地(包括日本),唯独韩国没有。“炸酱面”“赤匪”“中国奴”等韩语中专门针对中国人的侮辱性名称也出现了,直至现在我在韩国BBS上还经常看到,频率之高让我非常愤怒。最近惊闻韩国庆祝“韩国炸酱面”诞生100周年,鉴于韩国人试图盗取“活字印刷术发明权”,考证出“西施可能是韩国人”,“孔子可能是韩国人”等等劣迹,我挺怕它们有朝一日说炸酱面也是韩国的发明。这就比较讽刺了,因为当年“炸酱面”是它们对中国人的一种侮辱称谓呢。

    2. 韩国的电视节目

    我为了提高自己的韩国语水平,每天坚持阅读韩国新闻,刚去韩国时每天都抽出点时间看韩语节目。后来我统计了一下,每天都能看到不少关于中国的消息,当然,几乎都是负面的,如果有说中国好的,那八九不离十最后都要表达这样一个意思,“中国如此发展会对韩国造成威胁”。不仅是新闻,一次在娱乐节目中看到过这样的场面:采访一个刚从中国回来的韩国女艺人,主持人问她中国如何,她笑嘻嘻的把中国批判一番,什么脏呀,烂呀,穷呀之类的,在场的观众也非常受用,台上台下笑成一片。对于很多韩国人来说,嘲笑中国是最能增强它们“民族自豪感”的事情了,于是它们乐于找出中国的各种弱点来嘲笑,新闻媒体也非常愿意配合民众的这种心理,想方设法挖出这些东西来供国民消遣。所以我有时很纳闷,它们的记者怎么能找到这么多反映中国贫穷落后的新闻,如果我是个没去过中国的韩国人,那么百分之百我会觉得中国是个可怕的国家,对中国不可能有一点好感。

    3.韩国焚烧中国国旗

    有了这样的媒体,这样的教育,韩国人对中国的反感和狂妄自大就很容易理解了。有网络文章说在韩国繁华的明洞街头出现过“中国人谢绝”的条幅,这个我相信,因为我曾经见过照片,而且不止一个中国朋友告诉我在韩国商店遭到营业员歧视的事。别说在韩国,就连在青岛,在北京望京,不也发生过韩国人店谢绝接待中国人的情况吗?04年高句丽历史事件闹得最厉害的时候我恰巧在韩国,我看见过韩国人焚烧中国国旗,在中国大使馆前示威,以至当时我有种想立刻逃离韩国的想法。后来在街上也遇到过不少宣传,讲东北甚至山东古代都是“三韩”的领土,我只能置之不理。

    4. 韩国迫切的去中国化

    至于剩下的所谓“儒家传统”,只是中国媒体的想当然罢了。韩国人是不会承认的,它们很早以前就开始做的就是割断所谓“韩民族”文化和中华文化的联系,也就是,“去汉化”。汉城改“首尔”的闹剧刚刚过去,这不,几个韩国议员又开始张罗把“汉江”改为“韩江”了。在韩国,“中医”被改名成“韩医”,并被作为高丽医学而拼命向世界宣传推广。针灸也被认为是韩国人发明的,我没看过大长今,不知道里面是不是存在歪曲,但朝鲜日报分明是报道了这个“发现”,并找到了个法国人作证,宣称要纠正世界人民的错误认识,把针灸重新还给韩国。“活字印刷术”也被认为是韩国人先发明,这与中国学者发生了争论,韩国专门建立了印刷术博物馆,把中国在“印刷术”方面的功绩完全抹去,只片面夸大宣传自己,并邀请各国客人免费参观,并经常在国际场合进行宣传。我有幸被邀参观过那个博物馆,我只能承认他们在这方面的确做的非常好,“谎言重复一百遍就成了真理”,韩国人用这种方式“虚构”真理非常在行。

    5.韩国对中国的文化剽窃

    我在韩国被多次问到:“中国有没有中秋节,中国有没有春节”之类的,不要笑,这其中很多是名牌大学博士,以至于我后来实在厌烦了答他们:“农历是中国人发明的,所有农历节日中国都有。”还有个韩国名校博士一次和我讨论,信誓旦旦的说甲骨文应该是从朝鲜半岛传到中原的,并引用了一些韩国学者的“论据”,遇到这样的事我都懒得争辩了,真希望他在国际学术会上做这个报告,也给西方人看看韩国学者的“风采”。后来我看了篇韩国学者的文章,乖乖,连大禹治水用的“神书”都是朝鲜半岛传过来的,对韩国学者的学术能力我简直找不到语言形容了,惊如天人。要知道韩国直到15世纪才有自己的文字,韩国建国后为了“去汉化”才禁止使用汉字的,它们的学者“参考”的史书几乎都是用汉字写成的中国史书,它们以前还根本没有文字记录的历史呢。

    5.你们中国有63层的建筑吗?

    我在一个韩国华人论坛上看到一篇文章,讲的是一些在韩国的中国人常常遇到的问题,当时我觉得很有意思,因为和我遇到过的几乎一模一样,看来大家都差不多。在此摘抄转载一下,我就懒得打字了。。。
        
        A 你父母是干什么的? 来韩国的都是中国的有钱人吧!
        
        B 中国有面包么?中国也有方便面吗?中国也有苹果吗?中国也有练歌房(卡拉ok) 么?中国也有台球厅么?中国也过春节呀!中国也有网吧?中国人也用手机吗?
        
        C 这个比较诡异:中国人洗澡么?
        为什么会问这个问题呢?因为前几年有一个去过中国的韩国人写了篇文章讲中国人如何不讲究个人卫生,夏天身上散发恶臭,结果被韩国好多网站和报纸都转载了,(我已经说过,韩国媒体是非常喜欢这类文章的,韩国民众也是非常乐意通过这类文章来满足自己“民族自豪感”的),非常出名,大概韩国人对中国人卫生状况不良的印象由此而来。。。
        
        D 针对朝鲜族朋友的,一般会问:“你们是不是都很想来韩国当韩国人呀?你们希不希望从中国独立”之类的问题,说到朝鲜族,感觉韩国人有两个标准,只要是在国际上得了奖或者出了名,那不管是中国朝鲜族还是韩裔美国人,那统统都叫“在外同胞”,要大肆宣传一番;不过要是中国朝鲜族在韩国作奸犯科之类的被抓住了,那媒体首先强调的是那个罪犯是中国人。
        
        E 韩国人在带领人参观的时候很喜欢问:"中国也有这么高的建筑吗?""中国也有地铁吗?转述两个好玩的例子(不是我亲身经历,虽然我也遇到过上述两个问题):
        
        “一次韩国朋友带领我们去汉城市内观光,参观了他们全国最高最自豪的“63大厦"(不太高,就63层),结果问我们:中国也有这么高的建筑吗?我们平时被他的类似问题已经折磨得受不了了,一哥们就说:没有,韩国的这建筑世界第一高。。。那韩国人听了想了想,说:美国有更高的,我们这个大概只是亚洲第一吧。。。”
        
        “还有一次,韩国友人带我们去汉城的一个市内公园玩,大家都知道韩国国小,能在汉城搞出块还不算小的地方种点花草树木就很不得了了,所以就礼节性的赞扬了一下,结果一韩国人自豪的不行,问我们:北京也有这样的市内公园吗?我们一哥们回答:我们有颐和园,比这个大。。。那家伙听了顿时不说话了,他再孤陋寡闻,颐和园的大名还是知道的,最近中国旅游广告比较多。。。”
        
        原文作者最后一段写的很好:
        
        “看了之后有什么感受,是不是很不爽?其实韩国人的这些表现也提醒了我们,现在中国正在变强大,越来越多的外国人来到中国,其中也不乏那些来自相对落后国家的人们,我们在和这些外国人接触的时候会不会也出现韩国人这种“暴发户“心态呢?为了满足自己的虚荣心而提些弱智的问题,虽然别人当场不说,但对中国整个的印象肯定会受到影响。。。所以大家都应该反思一下,有则改之,不要让别人也觉得我们泱泱大中华的国民和韩国人一样小肚鸡肠,狂妄无知。”

    6.韩国与中国的领土之争

    说到韩国和中国的领土争端,相信不少中国人都要哑然失笑,隔着个海,还有领土争端?正如我在前面已经提到,韩国经过几十年的教育,现在韩国人一致认为,“高句丽”是它们“韩民族”的祖先,“高句丽历史”是韩国历史。04年由于中国的“东北工程”将高句丽史列为中国史一部分曾引发了中韩外交冲突,在媒体的推波助澜下,韩国国内的反华情绪非常高涨。至于真相如何,我这里就不深入讨论了,把工作留给学者,有兴趣的看官可以去查查相关资料
        
        但那些绑着写有“还我河山”四个鲜红大字布条的韩国人时常会成群结队出现在吉林吉安,延边,或者长白山。我看了朝鲜日报做的调查,居然过半的韩国年轻人赞成“夺回”“满洲(东北)和间岛(吉林延边)”。还是那句话,“谎言重复一百遍就成了真理”,韩国在高句丽问题上已经完成了发动群众的工作,而中国人大概很少有人知道高句丽,说不定还有不少人赞成韩国的观点,却不知道这个争端关系到了东北的归属。
        
        
        如果高句丽历史争论只是做秀,为将来做准备的话,那么延边和黄海领土争端已经摆在面前。
        
        中国与朝鲜和韩国存在着黄海大陆架的争议。中国主张按自然延伸原则划界(对待日本也是如此,因为我们的大陆架延伸更远),但韩国主张按中间线原则划界。这样,中韩双方便产生了6万平方公里的争议区。具有讽刺意味的是,韩国在黄海上对于中国主张中间线原则,而在东海上对于日本却主张采用自然延伸原则,完全没有原则性,只希望两边都占便宜。1991年5月至8月间,韩国在没有与中国达成协议的情况下,连续在中方黄海水域进行石油钻探活动,遭到强烈抗议。2004年7月,韩国还联合日本,在中国东海中方一侧的大陆架进行石油钻探,也遭到中国的抗议。
        
        此外,中韩两国在东海还有12万平方公里的争议区。中国主张按自然延伸原则与其划界,而韩国则主张按和划分黄海大陆架相同的中间线划分东海大陆架,两线之间便形成了12万平方公里的争议区。1974年1月30日,韩国与日本政府签订东海《共同开发大陆架协定》,开发石油和天然气等。中国政府曾发表声明,指出上述协定是非法的、无效的。
        
        韩国汉城市议会2005年10月24日召开第159次临时会议,制定了所谓的旨在“废除《间岛条约》”的决议案,决议案认为“间岛原是韩国领土”,因中国清朝与日本签约而被“割让”。决议案称,此举从国际法上看“违背当事人的意志”,所以韩国认为中日之间签署的《间岛条约》“根本无效”。又称,国际法认为,即使条约有“不妥之处”,在签定一百年(2009年)之后,通常也被视为有效。因此,决议案认为韩国政府应该为“找回”间岛及时向国际法院提起诉讼。
        
        “间岛”,原名“垦岛”(因大批朝鲜移民越界垦殖而名),系图们江北岸吉林省延边地区和龙县光霁峪前的一处滩地,自古系中国领土。清政府与朝鲜政府曾多次勘定国界,确定该地为中国领土。
        
        后来日本捏造所谓“间岛悬案”,并且恶意歪曲所谓的“间岛”范围,将纵十里、宽一里的滩地,扩大到“海兰河以南、图们江以北,宽约二三百里,长约五六百里之地”,即中国延吉、汪清、和龙、珲春四县地区,妄图一举侵吞这些地方。经过中国官员和学者的多方努力,最终挫败了日本的这一侵略图谋。1909年9月4日中日双方代表在北京签订《中韩界务条款》,即所谓的“间岛协约”。
        
        
        可以看出,韩国和中国是确实存在领土争端的,但中韩政府目前比较务实,特别是中国现在面临日美的压力,又要和平崛起,所以对以上的争端都做了最低调的处理。韩国政府也不敢造次,所以中韩间至今没有发生什么大的冲突。但韩国媒体向来有煽风点火,制造反华情绪的“光荣传统”,再加上其教育部门的作用,现在几乎所有的韩国人都认为中国“侵占”了它们的领土,其险恶用心不能不察。

    7. 韩国人的特性总结

    最后总结一下“大韩民族”的特性,在我看来,韩民族和日本民族是最相似的,特别是经过50年日本殖民统治,它们的共同点相当多。
        
        (1),国土狭窄,自然资源贫乏,严重依赖国外市场。日本好歹有30万平方公里的土地,韩国只有不到10万。经济都是外向型,原料基本靠进口,日本历史上强盛时走上了武力扩张之路。
        
        (2),单一民族,排他性非常强,狭隘民族主义盛行。日本右翼分子让中国人愤怒,但韩国更加狭隘极端的民族主义却时常让我冒冷汗,真庆幸它们至今仍然分裂,没有强大的实力。
        
        (3),为了“民族自豪感”,不惜篡改历史。记得有文章说日本人考古作假,让人鄙视。不过后来见了韩国人的“考古”,我倒觉得至少日本人还想着去做假证据,韩国人甚至把这一步都省了,还把成果出来大肆宣传。我不知道日本是不是也搞“去汉化”,但韩国搞得也太离谱了一点。
        
        (4),没有继承到儒家的真髓,形成了自己独特的文化。儒家强调“仁”,这很难和日本帝国主义联系到一起。而韩国的那种社会风气和韩国人的诸多品行也难和“仁”和“礼”联系到一起。所以说它们皮毛和架子是继承了,而且比我们做的还要“儒家”,但真正理解了吗?我看未必。
        
        
        (5),韩日战后经济发展模式基本一致,当然是韩国照搬日本经验和体制。所以韩国精英们对日本是相当推崇的,几乎达到了言必称日本的地步。至于国内大肆宣扬的“反日”,抱歉,我在韩国还真没感觉出来,身边的韩国人全套日本电器,倒是咱们几个“穷苦”中国人买了比较廉价的韩国产品支援了他们的三星LG。韩国国产车确实满街跑,日本车很少,不过去江南的富人区看看那里lexus也不少,原因很简单,贸易保护嘛,价高老百姓买不起。这里说句题外话,国内的车市,现在奇瑞吉利几个越卖越好,真高兴,这才是咱们的中国企业,不要贸易保护,和合资,外资企业硬碰硬,这样成长起来才有竞争力,我看好中国汽车。

    8. 最后:从韩国认清我们的民族之路

    韩国人完全可以正确面对历史,从现在开始扎扎实实建立自己的本民族文化。但是,他们不是这样,极力否认中华文化对韩国的影响,其实中国政府和人民从来没有把自己的文化强加给他们。他们这样,是自己的掩耳盗铃,此地无银三百两。

       有一次,我对韩国同事说,你们何必呢,中国又没有强加说韩国文化发源于中华汉族,你们极力否认,这不是不打自招吗?
       韩国对美国军队驻扎在自己的国土;对韩国的青年作为美国的炮灰派去伊拉克;对历史上曾经受日本的欺负凌辱;对朝鲜半岛的分裂;对曾经是中国的附属国,基本没有自己的本民族文化,感到深深的自卑和屈辱。我在韩国期间,电视报道,一个韩国人在伊拉克被当地民族激进分子作为人质,经过几天,最后被杀害,电视全程报道跟踪了这样一个事件。
       恰好后来中国福建的民工也被伊拉克当地民族激进分子作为人质,经过中国政府的斡旋和全力营救,福建民工被安全释放,这件事情,更在韩国人内心激起涟漪,感到自己民族的悲哀和国家的弱小。
       所以,综观韩国的历史,我们就不难理解韩国人偏执的爱国情怀,这其中有非常深刻自卑和狭隘心理。
       我们要爱国,但是,绝对不是学习韩国这样的态度。
       本来,韩国人如果能够庄敬自强,正视本民族的优劣,奋发图强,完全可以取得世人的尊重。
       但是,他们选择了另外的思维,阿Q精神,粉饰自己的历史,粉饰自己的文化,粉饰自己的现实生活,在对外输出的文化节目上粉饰和包装,俊男美女。
       本来这是一件小事情,但是当一个国家民族,津津乐道,满足于这样的表象;以为依靠几个明星就是横扫中国和亚洲,就是一种畸形现象了。
       所以,现在的韩国人,以嘲笑和蔑视中国,来平衡自己的畸形变态心理,以贬低中国证明自己的优越,而这种现象是发生在韩国的主流媒体上,发生在韩国知识精英阶层上,不是发生在一般的平民百姓身上,所以就不得不让我深思。
    中国有古语:知耻而后勇,有容乃大。所以有历史上强盛的中国,中华文化容纳、同化了历史上的很多民族,使中国成为一个多元的各民族并存的国家。
        我们不要妄自菲薄,走出去看看,你们会发现,今天的中国政府,今天的中国人民,在走一条走向富强的、有尊严的康庄大道。
       虽然这条道路不平坦,虽然我们有很多的不足,虽然我们现在的环境还不够清洁,政治不够民主,百姓不够富裕。但是你们可以看看20年前的韩国、台湾和新加坡,他们那时候有什么清洁、民主。
       国家的发展需要一个过程,需要我们的自尊自爱,和奋发图强。
       今天的中国,正视自己的不足,正在卧薪尝胆,我们为自己是中华民族的一员而自豪。

    当然,我们完全木必要刻意地去诋毁或者丑化他们,历史、现实究竟是什么样子,大家都很清楚。贴这篇帖子也并不是想反对韩国什么的,只是让大家对韩国有一个正确的认识。
    大家都是理智的,对吧?

    PS:篡改历史和武力侵略同等罪名,无耻之徒!
  • 什么是敏捷开发?

    2007-11-07 22:59:54

    敏捷开发(agile development)是一种以人为核心、迭代、循序渐进的开发方法。在敏捷开发中,软件项目的构建被切分成多个子项目,各个子项目的成果都经过测试,具备集成和可运行的特征。简言之,就是把一个大项目分为多个相互联系,但也可独立运行的小项目,并分别完成,在此过程中软件一直处于可使用状态。

        敏捷开发是全新理论吗?答案莫衷一是。细心的人们可以发现,敏捷开发其实借鉴了大量软件工程中的方法。迭代与增量开发,这两种在任何一本软件工程教材中都会被提到的方法,在敏捷开发模式中扮演了很重要的角色。再向前追溯,我们还也可见到瀑布式与快速原型法的影子,也许还有更多。

        改善,而非创新。敏捷开发可理解为在原有软件开发方法基础上的整合——取其精华,去其糟粕。因此敏捷开发继承了不少原有方法的优势。“在敏捷软件开发的过程中,我们每两周都会得到一个可以工作的软件,”Fowler介绍,“这种非常短的循环,使终端客户可以及时、快速地看到他们花钱构建的软件是一个什么样的结果。”

        也许是因为时间关系,Fowler只说出了这些优势中的一部分。允许开发过程中的需求变化、通过早期迭代可以较早发现风险、使代码重用变得可行、减少项目返工……借鉴了众多先进方法和丰富经验,拥有的众多优势使得敏捷开发看来已经成为解决软件危机的标准答案。

        然而,我们不得不面对的现实却是,模式与方法的优化并不意味着问题的终结。作为一种开发模式,敏捷开发同样需要面对众多挑战。

        大项目的拆分意味着更多子项目的出现,协调这些同步或异步推进的子项目,合理的资源调配都将变得更加复杂。另外,在当前项目和项目组普遍“增容”的情况下,遇到的问题同样成倍增长。人的重要性被提到了更高的高度,而缺乏有效协调手段,减少人员流动和项目变更对整个项目造成的影响也将成为一大挑战……新方法带来众多便利的同时,也相应引发了几乎同样多的问题。

        敏捷开发(agile development)概念从2004年初开始广为流行。Bailar非常支持这一理论,他采取了"敏捷方式"组建团队:Capital One的"敏捷团队"包括3名业务人员、两名操作人员和5~7名IT人员,其中包括1个业务信息指导(实际上是业务部门和IT部门之间的"翻译者");另外,还有一个由项目经理和至少80名开发人员组成的团队。这些开发人员都曾被Bailar送去参加过"敏捷开发"的培训,具备相关的技能。

        每个团队都有自己的敏捷指导(Bailar聘用了20个敏捷指导),他的工作是关注流程并提供建议和支持。最初提出的需求被归纳成一个目标、一堆记录详细需要的卡片及一些供参考的原型和模板。在整个项目阶段,团队人员密切合作,开发有规律地停顿--在9周开发过程中停顿3~4次,以评估过程及决定需求变更是否必要。在Capital One,大的IT项目会被拆分成多个子项目,安排给各"敏捷团队",这种方式在"敏捷开发"中叫"蜂巢式(swarming)",所有过程由一名项目经理控制。

        为了检验这个系统的效果,Bailar将项目拆分,从旧的"瀑布式"开发转变为"并列式"开发,形成了"敏捷开发"所倡导的精干而灵活的开发团队,并将开发阶段分成30天一个周期,进行"冲刺"--每个冲刺始于一个启动会议,到下个冲刺前结束。

        在Bailar将其与传统的开发方式做了对比后,他感到非常兴奋--"敏捷开发"使开发时间减少了30%~40%,有时甚至接近50%,提高了交付产品的质量。"不过,有些需求不能用敏捷开发来处理。" Bailar承认,"敏捷开发"也有局限性,比如对那些不明确、优先权不清楚的需求或处于"较快、较便宜、较优"的三角架构中却不能排列出三者优先级的需求。此外,他觉得大型项目或有特殊规则的需求的项目,更适宜采用传统的开发方式。尽管描述需求一直是件困难的事,但经过阵痛之后,需求处理流程会让CIO受益匪浅。

        敏捷开发是由一些业界专家针对一些企业现状提出了一些让软件开发团队具有快速工作、响应变化能力的价值观和原则,并于2001初成立了敏捷联盟。他们正在通过亲身实践以及帮助他人实践,揭示更好的软件开发方法。通过这项工作,他们认为:

    ·个体和交互 胜过 过程和工具
    ·可以工作的软件 胜过 面面俱到的文档
    ·客户合作 胜过 合同谈判
    ·响应变化 胜过 遵循计划

    并提出了以下遵循的原则:

    ·我们最优先要做的是通过尽早的、持续的交付有价值的软件来使客户满意。
    ·即使到了开发的后期,也欢迎改变需求。敏捷过程利用变化来为客户创造竞争优势。
    ·经常性地交付可以工作的软件,交付的间隔可以从几个星期到几个月,交付的时间间隔越短越好。
    ·在整个项目开发期间,业务人员和开发人员必须天天都在一起工作。
    ·围绕被激励起来的个体来构建项目。给他们提供所需的环境和支持,并且信任他们能够完成工作。
    ·在团队内部,最具有效果并富有效率的传递信息的方法,就是面对面的交谈。
    ·工作的软件是首要的进度度量标准。
    ·敏捷过程提倡可持续的开发速度。责任人、开发者和用户应该能够保持一个长期的、恒定的开发速度。
    ·不断地关注优秀的技能和好的设计会增强敏捷能力。
    ·简单是最根本的。
    ·最好的构架、需求和设计出于自组织团队。
    ·每隔一定时间,团队会在如何才能更有效地工作方面进行反省,然后相应地对自己的行为进行调整。

        敏捷设计就是一个过程,不是一个事件。它是一个持续的应用原则、模式以及实践来改进软件的结构和可读性的过程。它致力于保持系统设计在任何时间都尽可能得简单、干净及富有表现力。请记住,敏捷开发人员不会对一个庞大的预先设计应用那些原则和模式。相反,这些原则和模式被应用在一次次的迭代中,力图使代码以及代码所表达的设计保持干净。 

  • [论坛] 职场最受欢迎的十大技能

    2007-11-05 13:06:50

    一个人掌握何种技能取决于他的兴趣、能力和聪明程度,也取决于他所能支配的资源以及制定的事业目标,拥有过硬技能的人有更多的工作机会。但是,由于经济发展前景不确定,掌握对你的事业有所帮助的技能显得尤为重要。最受雇主欢迎的十种技能。

      一、解决问题的能力

      每天,我们都要在生活和工作中解决一些综合性的问题。那些能够发现问题、解决问题并迅速作出有效决断的人行情将持续升温,在商业经营、管理咨询、公共管理、科学、医药和工程领域需求量骤增。

      二、专业技能

      现在,技术已经进入了人类活动的所有领域。工程、通讯、汽车、交通、航空航天领域需要大量能够对电力、电子和机械设备进行安装、调试和修理的专业人员。

      三、沟通能力

      所有的公司都不可避免地面临内部雇员如何相处的问题。一个公司的成功很多时候取决于全体职员能否团结协作。因此,人力资源经理、人事部门官员和管理决策部门必须尽量了解职员的需求并在允许的范围内尽量予以满足。

      四、计算机编程技能

      如果你能够利用计算机编程的方法满足某个公司的特定需要,那么你获得工作的机会将大大增加。

      五、信息管理能力

      信息是信息时代经济系统的基础,掌握信息管理能力在绝大多数行业来说都是必须的。系统分析员、信息技术员、数据库管理员以及通信工程师等掌握信息管理能力的人才将会非常吃香。

      六、理财能力

      随着平均寿命的延长,每个人都必须仔细审核自己的投资计划以保证舒适的生活以及退休后的生活来源。投资经纪人、证券交易员、退休规划者、会计等职业的需求量也将继续增加。

      七、培训技能

      现代社会一天产生和搜集到的数据比古代社会一年的还要多。因此,能够在教育、社区服务、管理协调和商业方面进行培训的人才的需求量逐年增加。

      八、科学与数学技能

      科学、医学和工程领域每天都在取得伟大的进展。拥有科学和数学头脑的人才的需求量也将骤增,以应对这些领域的挑战。

      九、外语交际能力

      掌握一门外语将有助于你得到工作的机会。现在热门的外语是英语、日语、韩语、法语和德语。

      十、商业管理能力

      在经济飞速发展的今天,企业管理人员能够掌握成功运作一个公司的方法是至关重要的。

      这方面最核心的技能一方面是人员管理、系统管理、资源管理和融资的能力;另一方面是要了解客户的需要并迅速将这些需要转化为商机。
  • [论坛] HR更关注应聘者跳槽思维:多次"跳"更值得信赖

    2007-10-19 10:06:29

    通常情况下,负责招聘的HR最担心的是花高薪把能人挖来后,对方干不了多久就走人。因此,大多数HR对多次跳槽者都心怀警惕。但不少用人单位不再紧盯应聘者的跳槽次数,而是关注其“跳槽思维”——在他们看来,冷静、理性、有规划的多次跳槽者,其实更值得信赖。

        在大型综合招聘会上,某中型民营企业人事主管冯先生介绍,眼下该公司空出的中高级岗位较多,都是面向有经验的求职者。因此,在招聘过程中,如何在跳槽者中“淘金”至关重要。

        面试中有名求职者小马,大学毕业2年不到,却已换了3份工作。“单从简历上看,该应聘者的跳槽频率并不低,但是不是就说明其职业稳定度不高呢?”冯先生表示,他在翻看对方简历后认为,小马的几次跳槽目标明确,职业轨迹清晰。

        小马的专业是物流,第一份工作是在一家私营企业做物流助理,负责一些简单的行政工作,工作半年不到,由于老板是夫妻两个,在行政管理上常出现公私不分的情况,因此小马跳槽到一家民营企业的武汉办事处,担任对外联系工作,一年后,再次离职,到一大型物流公司担任普通职员。

        冯先生表示,从小马先后两次的离职及叙述中,他认为小马对自己的职业定位较清楚,知道自己应该往什么方向努力。“类似这种离职的人,是在变化中寻求稳定,在几次离职换工作中,提高自身的能力,同时也提升了个人职业竞争价值。”这样的人,没理由不用。

        但同样是高频率跳槽者,还有一种人,并不清楚自己需要什么样的工作,更不明白自己的职业目标在哪里,东家西家到处乱跳。“这样的人我们一概拒绝。要熟悉某个行业,至少需要半年的时间,那种还没有看清楚就贸然下结论说自己不适合这份工作的人,其实是对自己的不负责任,企业当然不会聘用。”
  • 有关的多线程测试

    2007-10-11 10:50:43

      Junit和许多开源软件项目集成在一起,但是Junit执行多线程的单元测试有一些问题。这篇文章介绍Junit的一个扩展类库———GroboUtils,这个类库被设计为来解决这些问题,并且使在Junit中进行单元测试成为可能。对Junit和线程有一个基本的理解是有好处的,但对于本篇文章的读者来说不是必需的。

    介绍

        如果你已经在一个开源的Java项目上工作,或者读了许多有关“极限编程”和其它“快速开发模式”的书籍,那么,你很有可能已经听说过有关Junit的事情。它是由Erich Gamma和Kent Beck编写的,Junit是一个Java的自动测试的框架,它允许你为你的软件定义的“单元测试”———不管是测试程序还是功能代码,通常都是基于方法调用方法的。

        Junit能在很多方面帮助你的开发团队———在一些文章中已经包含了很多这方面的介绍。但从一个开者到另一个开发者,Junit实际上只专箸于两件事:

    1、它强制你使用自己的代码。你的测试代码只是作为你的产品代码的客户端,从客户端的描述所获得的对你的软件的了解,能够帮助你标识出在API中的错误以及怎样改进代码,使其最终达到可以使用的目的。

    2、它会给你对软件中改变带来信心,如果你的测试用例被中断,你就是立刻知道错误。在一天工作结束的时候,如果测试提示是绿色的,则代码是正确,你可以自信的检查它。

        但是Junit不是解决所有软件测试中问题,第三方的扩展类库,例如HttpUnit,JwebUnit,XMLUnit等,已经认识到这些框架中不足,并且通过添加功能弥补不足,这些不足之一就是Junit不包含多线程的单元测试。

        在这篇文章中,我们会看到一个很少有人知道的解决这个问题的扩展类库。我们通过建立Junit框架开始,并且运行一个例子来展示Junit在线程没试中的不足。在我们认识了Junit在线程测试方面的不足之后,我们通过一个使用GroboUtils框架的例子来讨论GroboUnitls

    线程回顾

        对于那些不熟悉线程的人来说,在这一点上是非常不安的(一点都不夸大),离开你的系统,我们将对线做一个简单的介绍。线程允许你的软件有多个任务,也就是说可以同时可做两件事情。
        在Khalid Mugal和Rolf Rasmussen的书(A Programmer's Guide to Java Certification)中,对线程做了下面这样的简短描述:
        一个线程是一个程序中的可执行单元,它是被独立执行的。在运行时,在程序中的线程有一个公共的内存空间,因此,能够共享数据和代码;也就是说,它们是轻量级的。它也共享正在运行程序的进程。
    Java 线程使运行时环境异步,它允许不同的任务同时被执行。(p.272)

        在web应用程序中,许多用户可能同时发请求给你的软件。当你写单元测试对你的代码进行压力测试时,你需要模拟许多并发事件,如果你在开发健壮的中间件,这样做是尤其重要的。对于这些组件,使用线程测试是一个好的想法。

    不幸的是,Junit在这方面是不足的。

    有关Junit和多线程测试的问题

        如果你想验证下列代码,你需要下载并安装Junit。按着指示去做,以便能够在Junit的网站能够找到它。不要过分追求细节,我们将简要的介绍Junit是怎样工作的。要写一个Junit的测试,你必须首先创建一个扩展于junit.framework.TestCase(Juint中的基本测试类)的测试类。

        Main()方法和suite()方法被用启动测试。无论是从命令行还是IDE集成开发环境窗口,必须确保junit.jar在你的CLASSPATH环境变量里指定。然后为BadExampleTest.Class类编译运行下列代码:
    import junit.framework.*;
    public class BadExampleTest extends TestCase {
    // For now, just verify that the test runs
    public void testExampleThread()
    throws Throwable {
    System.out.println("Hello, World");
    }
    public static void main (String[] args) {
    String[] name =
    { BadExampleTest.class.getName() };
    junit.textui.TestRunner.main(name);
    }
    public static Test suite() {
    return new TestSuite(
    BadExampleTest.class);
    }
    }

        运行BadExampleTest来验证所建立的每一件事情的正确性。一旦,main()被调用,Junit框架将自动的执行任意一个用“test”开关命名的方法。继续并试着运行测试类。如果你正确的做了每一件事,它应该在输出窗口打印出“Hello World”。
        现在,我们要给程序添加一个线程类。我将通过扩展java.lang.Runnable接口来做这件事情。最后,我们将改变策略,并且扩展一个使线程自动创建的类。
    在DelayedHello的构造器中,我们创建一个新的线程并且调用它的start()方法。
    import junit.framework.*;
    public class BadExampleTest extends TestCase {
    private Runnable runnable;
    public class DelayedHello
    implements Runnable {
    private int count;
    private Thread worker;
    private DelayedHello(int count) {
    this.count = count;
    worker = new Thread(this);
    worker.start();
    }
    public void run() {
    try {
    Thread.sleep(count);
    System.out.println(
    "Delayed Hello World");
    } catch(InterruptedException e) {
    e.printStackTrace();
    }
    }
    }

    public void testExampleThread()
    throws Throwable {
    System.out.println("Hello, World"); //1
    runnable = new DelayedHello(5000); //2
    System.out.println("Goodbye, World"); //3
    }
    public static void main (String[] args) {
    String[] name =
    { BadExampleTest.class.getName() };
    junit.textui.TestRunner.main(name);
    }
    public static Test suite() {
    return new TestSuite(
    BadExampleTest.class);
    }
    }

    testExampleThread()方法实际上称不上是一个测试方法,实际上,你想使测试自动化,并且不想把检查结果输出到控制台,但是,这里却是这样的,因此,这一点示范了Junit是不支持多线程的。
    注意:testExampleThread()方法执行三项任务:
    1、 打印“Hello,World”;
    2、 初始化并起动一个支持打印“Delayed Hello World.”线程;
    3、 打印“Goodbye,World”。

        如果你运行这个测试类,你会注意到一些错误。TextHellWorld()方法像你期望的那样运行和结束。它没有发出任何有关线程的异常,但是你却不会接受到来自线程的返回信息。注意,你不会看到“Delayed Hello World”。为什么?因为线程还在激活状态的时候,Junit已经执行完成。问题发生在下面这行,使线程执行结束的时候,你的测试不能反映出它的执行结果。这个问题行是在Junit的TestRunner中。它没有被设计成搜寻Runnable实例,并且等待这些线程发出报告,它只是执行它们并且忽略了它们的存在。因为这个原因,几乎不可能在Junit中编写和维护多线程的单元测试。

    进入GroboUtils

        GroboUtils是Matt Albrecht编写的一个开源项目,它的目标是扩展Java的测试可能性。GroboUtils被发布在MIT许可下,这使它可以很友好的包含到其它的开源项目中。

    Grobo TestingJUnit 子项目

        GroboUtils被列入与同类测试方面有关的试验的子项目。这篇文章的焦点集中在Grobo TestingJUnit 子项目,它为Junit引入了一个支持多线程测试的扩展类库。(这个子项目还引入了集成测试和严重错误的概念,但是这些特征超出了这篇文章所讨论的范围。)

        在GroboTestingJUnit子项目内是BroboTestingJUnit-1.1.0-core.jar类库,它包含了MultiThreadedTestRunner和TestRunnable类,这两个类是对Junit进行扩展处理多线程测试所必须的。

    TestRunnable类

        TestRunnalbe类扩展了junit.framework.Assert类并且实现了java.lang.Runnable接口。你可以在你的测试类内定义TestRunnable对象做为内隐类。虽然,传统的线程类实现一个run()方法,但是你的嵌套TestRunnable类必须实现runTest()方法来替代run()方法。这个方法将被MultiThreadedTestRunner类在运行时调用,因此你不应该在构造器中调用它。

    MultiThreadedTestRunner类

        MultiThreadedTestRunner是一个允许把异步运行的线程数组放入Junit内一个框架。这个类在它的构造器中接受一个TestRunnable实例的数组做为参数。一旦建立了这个类的一个实例,它的runTestRunnables()方法就应该被调用开始执行线程测试。

        和标准的JunitTestRunner不一样,MultiThreadedTestRunner将等待,直到所有的线程执行终止退出。这样就强制Junit在线程执行任务的时候进行等待,从而巧妙的解决了我们前面提出的问题。让我们来看一下GroboUtils和Junit是怎样集成的。

    编写多线程测试

        现在把上面例子中的内隐类扩展自net.sourceforge.groboutils.junit.vl.TestRunnable包,我们必须像下面这样来重写runTest()方法。
    private class DelayedHello
    extends TestRunnable {
    private String name;
    private DelayedHello(
    String name) {
    this.name = name;
    }
    public void runTest() throws Throwable {
    long l;
    l = Math.round(2 + Math.random() * 3);

    // Sleep between 2-5 seconds
    Thread.sleep(l * 1000);
    System.out.println(
    "Delayed Hello World " + name);
    }
    }

        这时,我们全然不用创建工作线程。MultiThreadedTestRunner将在底层做这件事情,你重写runTest()方法来替实现run()方法,runTest()方法被后面的MultiThreadedTestRunner类调用———我们自己不会调用它。
    一旦TestRunnable被定义,我们必须定义新的测试用例。在我们的testExampleThread()方法中,我们实例化了几个TestRunnable对象,并且把它们添加到一个数组中。然后,示例化MultiThreadedTestRunner类,把TestRunnable对象数组做为参数传递给这人类的构造子函数。现在,我们有了一个MultiThreadedTestRunner类的实例,我们就可以调用它的runTestRunnables()方法来执行测试。

        MultiThreadedTestRunner(和Junit中的TestRunner不一样)在继续执行之前,将等待每一个线程运行终止。它也为通过构造器传递给它的每个TestRunnalbe对象创建工作线程并且调用异步的start()方法。这就意味着你没有必要通过创建你自己的线程来跳过这个障碍———MultiThreadedTestRunner会为你做这件事。下面是ExampleTest的最终版:
    import junit.framework.*;
    import net.sourceforge.groboutils.junit.v1.*;
    public class ExampleTest extends TestCase {
    private TestRunnable testRunnable;
    private class DelayedHello
    extends TestRunnable {
    private String name;
    private DelayedHello(
    String name) {
    this.name = name;
    }
    public void runTest() throws Throwable {
    long l;
    l = Math.round(2 + Math.random() * 3);
    // Sleep between 2-5 seconds
    Thread.sleep(l * 1000);
    System.out.println(
    "Delayed Hello World " + name);
    }
    }
    /**在你的测试用例中使用MultiThreadedTestRunner,
    * MTTR需要一个TestRunnable对象做为它的构造器的参数

    * MTTR创建以后,调用runTestRunnables()方法来运行它
    */
    public void testExampleThread()
    throws Throwable {

    //实例化 TestRunnable 类
    TestRunnable tr1, tr2, tr3;
    tr1 = new DelayedHello("1");
    tr2 = new DelayedHello("2");
    tr3 = new DelayedHello("3");

    //把实例传递给 MTTR
    TestRunnable[] trs = {tr1, tr2, tr3};
    MultiThreadedTestRunner mttr =
    new MultiThreadedTestRunner(trs);
    //执行MTTR和线程
    mttr.runTestRunnables();
    }
    /**
    * 标准的 main() 和 suite() 方法
    */
    public static void main (String[] args) {
    String[] name =
    { ExampleTest.class.getName() };
    junit.textui.TestRunner.main(name);
    }
    public static Test suite() {
    return new TestSuite(ExampleTest.class);
    }
    }

        上面的例子中,每个线程将会在你发出测试指令后,在2到5秒之间向你返回它们的输出,它们不仅按时间显示,而且是以一个随机的顺序来显示。这个单元测试只有所有的线程都执行完成后才会结束。由于外加了MultiThreadedTestRunner,所以Junit继续执行测试用例之前,必须耐心的等待TestRunnables执行完成它们的工作,做为可选项,你可以为MultiThreadedTestRunner的执行分配最大的执行时间(这样以便你脱离线程,而不挂起测试)。
    要编译运行ExampleTest,你必须在你的CLASSPATH环境变量中指定junit.jar和GroboUtils-2-core.jar两个类库的位置。这样你就会看到每人线程以随机的顺序来输出 “Delayed Hedllo World”

    结束语

        写一个多线程的单元测试不用感到苦脑,GroboUtils类库为编写多线程的单元测试提供了一个清晰简单的API接口,通过把这个类库添加到你的工具包中,你就可以把单元测试扩展到模拟繁重的WEB网络通讯和并发的数据库处理,以及对你的同步方法进行压力测试。


  • nmon 性能:分析 AIX 和 Linux 性能的免费工具

    2007-09-30 00:02:13

    nmon 性能:分析 AIX 和 Linux 性能的免费工具

    发布: 2007-9-29 09:47 | 作者: Nigel Griffiths | 来源: IBM | 查看: 0次

    这个免费工具使您能够在一个屏幕上查看大量的信息。尽管 IBM 没有提供对该工具的正式支持,并且您在使用它的时候必须自己承担相应的风险,但是您可以从中获得大量有价值的性能统计信息。如果有一个免费工具可以提供您所需要的所有信息,那么为什么还要使用五个或六个不同的工具呢?

    用法说明:这个nmon工具并未受到正式支持。没有提供或隐含任何保证,并且您无法从 IBM 获取相关的帮助。

    nmon工具运行于:

    • AIX® 4.1.5、4.2.0、4.3.2 和 4.3.3(nmon Version 9a:该版本的功能已经确定,并且不会对其进行进一步的开发。)
    • AIX 5.1、5.2 和 5.3(nmon Version 10:该版本现在支持 AIX 5.3 和基于 POWER5™ 处理器的计算机,并且提供了 SMT 和共享 CPU 微分区的支持。)
    • pSeries® p5 和 OpenPower™ 上的 Linux™ SUSE SLES 9、Red Hat EL 3 和 4、Debian
    • Linux SUSE、Red Hat 和许多最新的 x86(32 位模式的 Intel 和 AMD)上的发布版
    • zSeries® 或 mainframe 上的 Linux SUSE 和 Red Hat

    nmon工具大约每六个月更新一次,或者在可用的新的操作系统发布版中对其进行更新。要将您的名字放入到请求更新的电子邮件列表中,请与 Nigel Griffiths 联系。

    这个工具可以与nmon 分析程序一同使用,后者将加载nmon的输出文件并自动地创建大量的图形。

    引言

    nmon工具可以为 AIX 和 Linux 性能专家提供监视和分析性能数据的功能,其中包括:

    • CPU 使用率
    • 内存使用情况
    • 内核统计信息和运行队列信息
    • 磁盘 I/O 速度、传输和读/写比率
    • 文件系统中的可用空间
    • 磁盘适配器
    • 网络 I/O 速度、传输和读/写比率
    • 页面空间和页面速度
    • CPU 和 AIX 规范
    • 消耗资源最多的进程
    • IBM HTTP Web 缓存
    • 用户自定义的磁盘组
    • 计算机详细信息和资源
    • 异步 I/O,仅适用于 AIX
    • 工作负载管理器 (WLM),仅适用于 AIX
    • IBM TotalStorage® Enterprise Storage Server® (ESS) 磁盘,仅适用于 AIX
    • 网络文件系统 (NFS)
    • 动态 LPAR (DLPAR) 更改,仅适用于面向 AIX 或 Linux 的 pSeries p5 和 OpenPower

    还包括一个用来从nmon的输出生成图形并创建可以在 Web 站点显示的 .gif 文件的新工具。

    有关详细信息,请参阅自述文件。





    回页首


    该工具的作用

    nmon工具可以帮助在一个屏幕上显示所有重要的性能优化信息,并动态地对其进行更新。这个高效的工具可以工作于任何哑屏幕、telnet 会话、甚至拨号线路。另外,它并不会消耗大量的 CPU 周期,通常低于百分之二。在更新的计算机上,其 CPU 使用率将低于百分之一。

    使用哑屏幕,在屏幕上对数据进行显示,并且每隔两秒钟对其进行更新。然而,您可以很容易地将这个时间间隔更改为更长或更短的时间段。如果您拉伸窗口,并在 X Windows、VNC、PuTTY 或类似的窗口中显示这些数据,nmon工具可以同时输出大量的信息。

    nmon工具还可以将相同的数据捕获到一个文本文件,便于以后对报告进行分析和绘制图形。输出文件采用电子表格的格式 (.csv)。





    回页首


    安装该工具

    该工具是一个独立的二进制文件(不同的 AIX 或 Linux 版本中该文件也有所不同),您可以在五秒钟内完成该工具的安装,如果您的输入速度更快的话,也许时间更短。安装过程非常简单:

    • nmonXXX.tar.Z文件复制到计算机。如果使用 FTP,请记住使用二进制模式。
      注意:示例中的 XXX 由实际的版本代替。
    • 要解压该文件,可以运行uncompress nmonXX.tar.Z
    • 要提取该文件,可以运行tar xvf nmonXX.tar
    • 阅读自述文件。
    • 要启动nmon工具,输入nmon
    • 如果您是 root 用户,可能需要输入./nmon

    使用 nmon 9 的附加说明,仅适用于 AIX 4

    1. 必须是 root 用户,或者通过输入下面的命令允许一般用户读取/dev/kmem文件(作为 root 用户):
      chmod ugo+r /dev/kmem

    2. 如果您需要磁盘统计信息,还可以运行下面的命令(作为 root 用户):
      chdev -l sys0 -a iostat=true

    如何以交互式的方式运行该工具

    要以交互式的方式运行该工具,请阅读该文件前页中的相关提示。然后启动该工具,并使用单键命令来查看您所需要的数据。例如,要获取CPU内存磁盘统计信息,启动nmon并输入:

    cmd

    如何在以交互式的方式运行该工具的同时,获取相关的帮助信息

    h键。

    附加帮助信息

    要获取附加的帮助信息,可以尝试下列方法

    • 输入nmon -?命令以获取简短的详细信息。
    • 输入nmon -h命令以获取完整的详细信息。
    • 阅读自述文件。

    如何将数据捕获到文件,便于以后进行分析和绘制图形

    运行带 -f 标志的nmon命令。有关详细信息,请参阅nmon -h。但是作为示例,可以尝试运行下面的nmon命令,在 1 小时内以 30 秒的时间间隔捕获数据快照:

    nmon -f -s 30 -c 120
    nmon -fT -s 30 -c 120

    第二行的命令还可以捕获消耗资源最多的进程。这两行命令都将在当前目录中创建输出文件,其名称为:

    <hostname>_date_time.nmon

    该文件采用逗号分隔值 (CSV) 的格式,并且可以将其直接导入到电子表格中。如果您使用的是 Lotus® 1-2-3,那么需要对该文件进行排序。(对于 Excel 版本的nmon分析程序,则不需要进行这个操作。)在 AIX 中,请遵循下面的示例:

    sort -A mymachine_311201_1030.nmon > xxx.csv

    关于如何节省时间的说明:

    • 要将nmon数据捕获文件加载到电子表格,可以查看电子表格文档中有关加载 CSV 数据文件 (.csv) 的内容。许多电子表格可以接受该数据,作为可加载的文件之一,或者提供完成这项任务的导入函数。许多电子表格具有固定数目的列和行。我建议您最多收集 300 个快照,这样就可以避免碰上这些问题
    • 当您将数据捕获到一个文件中时,nmon将断开与Shell 的连接以确保它能够连续运行,即使您在此过程中执行了注销操作。这意味着nmon可能出现故障,即使它仍然在后台运行。要查看该进程是否仍在运行,可以输入:
      ps ?ef | grep nmon

    • 有关您的特定的操作系统上运行的nmon版本的详细信息,请阅读自述文件。
    • 面向 AIX 5 的nmonVersion 10 不再使用/dev/kmem,仅使用一些公开的 API。因此,您不需要更改 /dev/kmem 的权限,并且不需要使用 32 位和 64 位版本的nmon
    • 对于 AIX 5.1、5.2 和 5.3,可以使用nmon10。
    • 从 ML03 AIX 中开始,不再报告 AIX 5.1 中的lslpp -Lcq bos.?p核心转储。另外,在升级到 AIX 5.2 ML5 后,Nigel Griffiths 忽略了 WLM 状态信息,而这些也是 AIX 错误。通过使用nmonVersion 10,可以避免这些问题。
    • 不要使用 Microsoft® Windows® Telnet 和大于 80 x 25 字符的窗口。许多开发人员使用 VNC 和 PuTTY 来显示来自 Windows 计算机的nmon,为什么不使用相同的方法呢!





    回页首


    AIX Version 10 中的 nmon 的新特性

    新特性 描述
    启动 目前还有一个称为"nmon"的小型 Shell 脚本,可以用来启动适当的nmon版本。将该脚本和nmon二进制文件放入到您的 $PATH 中,然后输入:nmon。该版本目前仅在 32 位模式下进行了编译。所以,它可以运行于 32 位和 64 位硬件。这是为了使它更容易安装和运行。
    N = NFS 对于nmon10 来说,NFS 是全新的特性。
    p = 分区 (Partitions) 该特性是为了共享 CPU 分区信息,这是 p5/AIX5.3 的重要特性。
    C = CPU 这是为了支持使用 32 个以上 CPU 的计算机,最多可以根据需要达到 128 个逻辑 CPU。
    c = CPU 如果您在 POWER5 上使用 AIX 5.3,并且处于共享 CPU 环境中,那么该特性可以提供关于物理 CPU 使用的详细信息。
    S = 子类 (Subclass) 该特性根据要求表示 WLM 的子类。
    a = 磁盘适配器 (Disk adapters) 提供磁盘适配器的详细信息,比如它们的完整类型。
    r = 资源 (Resources) 其中包括以 MHz 为单位的 CPU 速度。
    k = 内核 (Kernel) 提供了一些新的字段。
    L = 大型页面 (Large pages) 提供了大型页面的状态信息,适用于追求高性能的用户。
    D = 磁盘 (Disk) 提供关于磁盘、磁盘类型大小、可用空间、卷组、适配器等更详细的信息。
    n = 网络 (Network) 提供关于网络适配器、MTU 和相关错误的详细信息。
    m = 内存 (Memory) 提供内存使用的更详细的信息,如系统(内核)和进程、活动虚拟内存。
    -B 这是移除封装的启动选项。




    回页首


    AIX 5 的 nmon 10 的输出示例

    图 1是屏幕输出的示例。它显示了 AIX 5 的起始屏幕,以及大量有价值的信息。


    图 1. AIX 5 的 nmon 10 的输出示例
    启动

    图 2说明了关于 CPU(这里是 4 CPU 的 POWER5 计算机,并打开了 SMT)、内存使用、内核内部统计和磁盘统计的详细信息。注意:这个逻辑分区 (LPAR) 占用了一半 CPU 中其授权值的 6 倍。


    图 2. CPU 详细信息
    CPU

    图 3显示了网络、NFS 统计信息和日志文件系统使用的详细信息。


    图 3. 网络详细信息
    网络

    在下面的图 4中显示了 POWER5 共享处理器微分区统计的详细信息。


    图 4. LPAR 详细信息
    LPAR

    图 5说明了 Linux 版本的nmon的详细信息,其中显示了 CPU(这里是 2 CPU 的 POWER5 计算机,并打开了 SMT)、LPAR 统计、内存使用、网络统计、文件系统使用和磁盘统计的详细信息。注意:该 LPAR 的物理 CPU 仅在 SUSE SLES9 Service Pack 1 和 Red Hat EL 4 Update 1 中是可用的。


    图 5. nmon 的 Linux 版本
    nmon_Linux1

    图 6显示了计算机、磁盘统计(详细模式)和主要进程的操作系统详细信息。


    图 6. nmon 的 Linux 版本(续)
    nmon_Linux2




    获取该工具

    下面是可用的下载选择:

  • Visual Unit 简介

    2007-09-29 23:40:07

    Visual Unit 是可视化C/C++单元测试工具,V2.0是在V1.0大量应用的基础上,完全重新设计的版本。

    适应性
    高度耦合的代码难于分割测试一直是单元测试的主要难点,VU2具有完善的桩功能,包括:补齐(自动生成未定义符号)、隔离(自动生成桩代码替换底层代码)、控制(在用例中随意控制底层代码的行为),从开始编码到升级维护的各个阶段,均可对任意层次、范围的代码实施分割测试。

    测试效果
    用人工设计的用例测试代码功能,用自动用例捕捉漏网之鱼。可轻松完成100%语句、条件、分支、路径覆盖,保证测试效果。

    测试效率
    自动生成测试代码和用例框架;功能强大的用例编辑器可快速建立用例集;无需编写代码即可随意控制底层代码行为;使用用例设计器高效找出遗漏用例;自动生成边界测试用例。能自动化的都已自动化,人的工作量已压缩到最低限度,保证了测试效率。

    开发效率
    编码过程中,自动同步更新,随时可以执行测试;自动显示输入输出数据,可用简单语法输出任意中间变量、表达式的值,自动显示代码执行状况,使程序行为一目了然,帮助整理和验证编程思维,并能快速排除错误;增强调试器功能,包括:可视化选择调试输入、自动中断、无限制重复或后退、调试过程中切换除入。无需增加工作时间和劳动强度,在原来用于编码的时间内可以同时完成编码和单元测试。
  • 富人和穷人 12个经典差异(转载)

    2007-09-13 12:44:13

    1 自我认知

    穷人:很少想到如何去赚钱和如何才能赚到钱,认为自己一辈子就该这样,不相信会有什么改变。

    富人:骨子里就深信自己生下来不是要做穷人,而是要做富人,他有强烈的赚钱意识,这也是他血液里的东西,他会想尽一切办法使自己致富。

    2休闲

    穷人:在家看电视,为肥皂剧的剧情感动得痛苦流涕,还要仿照电视里的时尚来武装自己。
    富人:在外跑市场,即使打高耳夫球也不忘带着项目合同。

    3交际圈子

    穷人:喜欢走穷亲戚,穷人的圈子大多是穷人,也排斥与富人交往,久而久之,心态成了穷人的心态,思维成了穷人的思维,做出来的是也就是穷人的模式。大家每天谈论着打折商品,交流着节约技巧,虽然有利于训练生存能利,但你的眼界也就渐渐囿于这样的琐事,而将雄心壮志消磨掉了。

    富人:与无数成功上进人士交往。成功+成功=最最成功!

    4学习

    穷人:学手艺

    富人:学管理

    5时间

    穷人:一个享受充裕时间的人不可能赚大钱,要想悠闲轻松就会失去更多赚钱的机会。穷人的时间是不值钱的,有时甚至多余,不知道怎么打发,怎么混起来不烦.如果你可以因为买一斤白菜多花了一分钱而气恼不已,却不为虚度一天而心痛,这就是典型的穷人思维。

    富人:一个人无论以何种方式赚钱,也无论钱挣得是多还是少,都必须经过时间的积淀.富人的玩也是一种工作方式,是有目的的.富人的闲,闲在身体,修身养性,以利在战,脑袋一刻也没有闲着;穷人的闲,闲在思想,他手脚都在忙,忙着去麻将桌上多摸几把。

    6归属感

    穷人:是颗螺丝钉。穷人以为出身卑微,却少安全感,就迫切地希望自己从属于并依赖于一个团体,于是他们以这个团体的标准为自己的标准,让自己的一切合乎规范,为团体的利益而工作,奔波,甚至迁徙.对于穷人来说,在一个著名的企业里稳定的工作几十年,有实习生一直干到高级主管,那简直是美得不能在美的理想。

    富人:那些团体的领导者通常都是富人,他们总是一方面向穷人灌输:团结就是力量,如果你不从属于自己的团体,你就什么都不是,一名不文.但另一方面,他们却从来没有停止过招兵买马,培养新人,以便随时可以把你替换掉。

    7投资及对待财富

    穷人:经济观点就是少用等于多赚,比如开一家面馆.收益率是100%,投入2,一年就净赚2,对于穷人来说很不错了。穷人即使有钱,也舍不得拿出来,即使终于下定决心投资,也不愿意冒风险,最终还是走不出那一步。穷人最津津乐道的就是鸡生蛋,蛋生鸡,一本万利......但是建筑在一只母鸡身上的希望,毕竟是那样的脆弱。

    富人:富人的出发点是万本万利.同样的开面馆,富人们会想,一家面馆承载的资本只有2,如果有一亿资金,岂不是要开5000家面馆?要一个一个管理好,大老板得操多少心,累白多少根头发呀?还不如投资宾馆,一个宾馆就足以消化全部的资本,哪怕收益率只有20%,一年下来也有2000万利润啊。

    8激情:能不能干成事,首先要看有没有激情

    穷人:没有激情。他总是按部就班,很难出大错,也绝对不会做到最好。没有激情就无法兴奋,就不可能全心全意投入工作。大部分的穷人不能说没有激情,看他的激情总是消耗在太具体的事情上:上司表扬了,他会激动;商店打折,他会激动;电视里破镜重圆了,他的眼泪一传一串往下流,穷人有的只是一种情绪。

    富人:"燕雀安知鸿鹄之志?""王侯将相,宁有种乎?"有这样的激情,穷人终将不是穷人!激情是一种天性,是生命力的象征,有了激情才有了灵感的火花,才有了鲜明的个性,才有了人际关系中的强烈感染力,也才有了解决问题的魄力和方法。

    9自信

    穷人:穷人的自信要通过武装到牙齿,要通过一身高级名牌的穿戴和豪华的配置才能给他们带来更多的自信,穷人的自信往往不是发自内心和自然天成的。
    富人:李嘉诚在谈到他的经营秘诀时说:"其实也没什么特别的,光景好时,决不过分乐观;光景不好时,也不过度悲观。其实就是一种富人特有的自信。自信才能不被外力所左右,自信才可能有正确的决定。

    10习惯

    穷人:有个故事,一个富人送给穷人一头牛。穷人满怀希望开始奋斗。可牛要吃草,人要吃饭,日子难过。穷人于是把牛卖了,买了几只羊,吃了一只,剩下来的用来生小羊.可小羊迟迟没有生出来,日子又艰难了。穷人把羊卖了,买成了鸡,想让鸡生蛋赚钱为生,但是日子并没有改变,最后穷人把鸡也杀了,穷人的理想彻底崩溃了,这就是穷人的习惯。

    富人:根据一个投资专家说,富人成功的秘诀就是:没钱时,不管多困难,也不要动用投资和储蓄,压力会使你找到赚钱的新方法,帮你还清帐单.这是个好习惯。性格决定了习惯,习惯决定了成功。

    11上网

    穷人:上网聊天,穷人聊天,一是穷人时间多,二是穷人的嘴天生就不能闲着.富人讲究荣辱不惊,温柔敦厚,那叫涵养,有涵养才能树大根深.穷人就顾不了那么多,成天受着别人的白眼,浑身沾满了鸡毛蒜皮,多少窝囊气啊,说说都不行?聊天有理!

    富人:上网找投资机会、学习管理知识。富人上网,更多的是利用网络的低成本高效率,寻找更多的投资机会和项目,把便利运用到自己的生意中来。

    12消费花钱

    穷人:买名牌是为了体验满足感,最喜欢试验刚出来的流行时尚产品,相信贵的必然是好的。富人:买名牌是为了节省挑选细节的时间,与消费品的售价相比,他们更在乎产品的质量,比如会买15元的纯棉T,也不会买昂贵的莱卡制品。

  • 在职场中如何建立个人品牌?

    2007-09-13 12:42:50

    一、给个人品牌一个准确定位。
        市场经济下,个人越来越注重个人品牌的塑造,那么什么是个人品牌呢?
        个人品牌可以这样理解:区别于别人的独特的品质,并被社会认可和接受的品牌。它包括个人技能专长、思想、观念、世界观、价值观、行为准则等一系列内容。个人品牌需要精心打造并向社会传播,更需要时间沉淀:优秀的个人品牌随着时间的推移会不断地增值;不良的个人品牌随着时间的推移逐步被社会淘汰。个人品牌不能随意塑造,要有明确的定位,建立个人品牌的第一件事就是要找出自己与他人不同的特质。影响一个人品牌的因素有五个能级模型:体能、技能、智能、势能及整合能。体能,是一个人的体力状态;技能,指一个人拥有一技之长和在某个领域的专业知识;智能,指一个人的经营管理才能和创新能力;势能,指一个人在社会层面上所处的位置,人际关系等;整合能,指一个人整合各种社会资源的能力,是一个人各种综合能力的集中体现。个人品牌的价值,就是自身能力的价值。我们可以从这几个问题,来测评一下自己的品牌价值:你的知名度如何?你以哪几件事闻名一时?你有几项技能比别人强?你过去的一年中学到了什么?你的履历表与别人有何不同?别人认为你最大的长处是什么?最值得人注意的个人特质是什么?你每一次都能完成既定的工作吗?你总是预先一步解决问题吗?好好想一想:你将如何与众不同?市场讲究产品细分,个人品牌同样如此。一提起篮球就想到姚明、易建联等,一提起导演就想到张艺谋、陈凯歌等,这就是个人品牌的魅力。
    二、 建立自己个性的视觉形象:
        建立个人品牌的首要条件就是让人们清楚的记得你,在这个极度商业化的社会里,人们每天直接和间接接触到的各类信息数不胜数,要让人们清楚的记得你的重要方法之一就是建立自己独特的个性的视觉形象。每提到姚明、Bill Gates等人,相信在很多人在脑海中就会有一定的刻板印象,因为那是长期对你的视觉冲击产生的个人品牌印象。无论你从事的那个行业,都要记住,一定要在业界经常保持有你的声音,你要抓住一切有可能的机会,在行业的论坛、会议、媒体上发表你的观点和构想。树立你自己鲜明的观点旗帜,并且不遗余力的捍卫她。吴敬琏、任志强、潘石屹等人观点鲜明,并寻找影响扩散面宽、快的媒体和场合发布,这样你就能获得知名度。其实,适度的包装和策划是必不可少的,但一定要围绕某专业领域的形象来设计个性的视觉形象,如果吴敬琏以拿个篮球穿运动衣的形象去传播自己,想想都很有意思了。
    三、 专精于你目前的工作并获得成绩。
        个人品牌是由一个接一个的工作来表现的。你应该将90%的时间用在拼命完成工作。所以你的工作日程表就是你的个人品牌建立的蓝图。争取在自己的行业内成为专家高手,并且要有令人叫绝的思想。重要的是取得举世瞩目的成就,成功的人士一般媒体乐于报道和传播。姚明—篮球;王石—房地产;马云—电子商务,等等,提到某人,必然联想到某个行业,这就是个人品牌的影响力。如果姚明、王石、马云等人没有在自己的行业内取得卓越成绩,也很容易被淡忘。
    四、 懂得扮演自己的公关经理,对个人品牌进行整合传播:。
    建立个人品牌,为的是提高知名度,需要利用每个机会,向别人推销自己。要掌握很好的口语表达的技巧。虽然不需要做一个演讲家,但一定能够清楚、从容的表达自己,要充满热情的说服别人。建立个人品牌的重要技巧,就是设法用心经营自己的人际网络,扩大自己的社交圈子,坚持每天都结识不同的人,增加能见度。广解善缘很重要:大家知道你想要什么、能力如何,有合适的机会自然就会想到你。信息时代,传播的速度和覆盖面是决定你是否能够得到超速发展的重要因素之一。你的个人视觉形象、观点论调、事件扩散、都需要通过各种媒体渠道去传播,使得有更多的人们记得你,认知你,关注你。和媒体保持密切和友好的关系有助于你的个人品牌的传播加速度的进行,特别是互联网。建立“个人品牌”需要建立和提高你的知名度,因此,你需要利用每个机会,像别人讲述自己的故事,比如说在BLOG内写自己的独特观点和视角,这需要你掌握专业知识并巧妙运用一些基本的语言技巧,并要琢磨如何简单明了的像别人传播你的品牌。同时,你需要分析你的目标客户经常出入的场合、接触的媒体等,来对你的“个人品牌”进行整合传播,让你的目标客户主动找你,你的品牌价值就会增加。网络红人“芙蓉姐姐”就是先在大学生云集的北大清华的BBS张扬自己的个性,在称赞和批判中提升了知名度,但其品牌生命力不强,因为靠一些哗众取宠的东西,没有自己的核心竞争力,是走不远的。企业品牌如此,个人品牌亦如此。
    五、个人品质是品牌的保障:
        建立个人品牌需要自己有足够承载品牌传播的平台,也就是你的个人素质,社会只相信有能力的人,并为他们预留着发展的空间,机会总是垂青有充分准备的人,个人素质的就象企业之产品,最基本特征是质量保障,只有产品质量过硬,才能声名鹊起。引申到个人品牌,最重要的就是品质保障。这体现在两方面,一方面是个人业务技能上的高质量。另一方面是人品质量,也就是既要有才更要有德。一个人,仅仅工作能力强,而道德水平不高是不会建立个人品牌的。 此外,切记:品牌最重要的就是要讲信誉,品牌不是个商标,而是信赖标记。要成功建立个人品牌,你必须绝对的诚信。
    六、 管理个人品牌:
        个人品牌一旦建立,并不能因此安枕无忧;有必要通过特定的手段对于个人品牌—不同对象对于个人的认知—进行有效的管理;可以根据自身的特色,精心地设计对外的所有信息:性格、爱好、经历、特长、业绩……让上述关于企业家自身的信息成为实现目的的手段。
    美国总统Clinton是否拥有个人品牌?答案是肯定的。这一至关重要的个人品牌当然需要有效的管理。实际上,他的一言一行、一举一动、着装方式、演讲内容都要经过其专业班子的精密策划和执行后,方能走向前台。企业家和明星,参与社会活动的形象和言语都是需要进行策划的,给不同受众传达不同风格和理念,从而维护其个人品牌形象。
    在树立个人品牌的过程中,可以通过亲身调查或者委派管理机构出面,与行业人士和媒体、消费者随时互动,以了解当前他们对于个人的认知情况:怎么看待本人?是喜欢还是排斥?是信任还是怀疑?是了解还是误解?内外部的认知永远不可能完全统一于个人品牌的识别,但是通过不懈的努力,两者之间可以达到较高程度的一致,此时的个人品牌可谓成功树立,并且将有助于个人战略、品牌、市场目标的达成。
    六、 维护个人品牌技巧:
        个人品牌一定是在互动的过程中得到升华,所以想了解在市场中运作的怎么样,一定要和你的目标客户沟通,了解他们的想法;很多歌星举办歌迷会就是非常好的方式。假如说,想获得更好的职业发展和收入待遇,那么一定要在猎头和行业内形成良好的口碑,提升个人形象,无疑能获得更好的职业前景;其次需要在行业内或者圈内,经常露脸,成为各种社交场所的熟面孔,让更多的人为你的品牌传播。影视圈不断传绯闻的现象,虽然很多有炒作嫌疑,但只要运用合理,职业人士同样可以借鉴;然后,推出自己的品牌宣言,如独特的价值主张、生活方式和个性,个人品牌宣言对个人定位的简洁陈述,也是你个人理念的有效传播形式之一。最后,建立个人品牌一定要注意自己的言行,言行一致,才会形成良好的品牌。网络发达的年代,一些个人品质上的任何闪失就会造成终身污点,对建立个人品牌非常不利,数不胜数的引咎辞职的情况,是对个人品牌的最大伤害。
    七、强大个人品牌的收益:
    1,   个人形象的进一步提升,得到更多认可。
    2,快速增长的收入,你的博学和智慧能给别人带来收益,同时也给自己带来价值提升。
    3,更多的客户和生意量,你的专业品质广为传播,生意就源源不断。
    4,知名度和美誉度,占领目标受众的心智资源,增加感知价值。
    5,   品牌身价,张艺谋是电影界的知名品牌,身价估计有40亿;姚明是中国身价最高的运动员,如果他在中国发展无论如何都受限制,一旦去了NBA,就成了知名全球的巨星。
     
    八、结束语:
    这是自我营销的年代,个人品牌层出不穷。树立个人品牌仅靠埋头苦干还不行,一定要走出去,让更多熟知你,了解你的品质,但也不能因此成为随意跳槽和加薪的理由,重要的是展现自己的价值,得到客户的认可,其实老板也是你的客户。树立个人品牌无疑是职场获胜的关键,如果你能建立一个可持续经营的个人品牌,运用好这个无形资产,你的收益将不同凡响。从现在起,重视你的个人品牌,让自己的个人价值得到飞跃!
  • Linux 下shell的编程详解

    2007-06-20 11:13:19

     

    *Shell是什么?
      任何发明都具有供用户使用的界面。UNIX供用户使用的界面就是Shell(DOS的command熟悉吧,但UNIX的要强大的多)。 Shell为用户提供了输入命令和参数并可得到命令执行结果的环境。
      为了不同的需要,UNIX提供了不同的Shell。现在的UNIX大部分都支持BourneShell,以下教程就以BourneShell(Bsh)为例,一步步的领略UNIX Shell的强大功能,占先其强大魅力,达到更方便灵活的管理、应用UNIX的目的。
      1.UNIX内核和Shell的交互方法
      启动UNIX时,程序UNIX(内核)将被调入计算机内存,并一直保留在内存中直到机器关闭。在引导过程中,程序 init将进入后台运行一直到机器关闭。该程序查询文件/etc/inittab,该文件列出了连接终端的各个端口及其特征。当发现一个活动的终端时, init程序调用getty程序在终端上显示login等登陆信息。(username和passwd),在输入密码后, getty调用login进程,该进程根据文件/etc/passwd的内容来验证用户的身份。若用户通过身份验证,login进程把用户的home目录设置成当前目录并把控制交给一系列setup程序。setup程序可以是指定的应用程序,通常setup程序为一个Shell程序,如:/bin/sh 即Bourne Shell(command出来了,呵呵)。
      得到控制后,Shell程序读取并执行文件/etc/.profile以及.profile。这两个文件分别建立了系统范围内的和该用户自己的工作环境。最后Shell显示命令提示符,如$。(这是以bsh为例,若是csh,为.cshrc,ksh为.kshrc,bash为. bashrc等等)    
      注:(不妨把/etc/.profile和.profile看成DOS的autoexec.bat 或 config.sys文件)
      当shell退出时,内核把控制交给init程序,该程序重新启动自动登陆过程。有两种方法使shell退出,一是用户执行exit命令,二是内核(例如root用kill命令)发出一个kill命令结束shell进程。shell退出后,内核回收用户及程序使用的资源。
      用户登陆后,用户命令同计算机交互的关系为:命令进程--->Shell程序--->UNIX内核--->计算机硬件。当用户输入一个命令,如$ls, Shell将定位其可执行文件/bin/ls并把其传递给内核执行。内核产生一个新的子进程调用并执行/bin/ls。当程序执行完毕后,内核取消该子进程并把控制交给其父进程,即Shell程序。例如执行:
        $ps
        该命令将会列出用户正在执行的进程,即Shell程序(下来详细说说,别急现在)和ps程序。若执行:
        $sleep 10 &
        $ps
      其中第一条命令将产生一个在后台执行的sleep子进程。ps命令执行时会显示出该子进程。
      每当用户执行一条命令时,就会产生一个子进程。该子进程的执行与其父进程或Shell完全无关,这样可以使Shell去做其他工作。(Shell只是把用户的意图告诉内核,然后该干嘛干嘛:)) 现在windows有个计划任务(在固定的时间,日期自动执行某任务),其实UNIX很早就有这个功能了,也就是所谓的Shell的自动执行。一些 UNIX 资源,如cron可以自动执行Shell程序而无需用户的参与,(这个功能好象在/var/spool/crotab目录里)。 Crontab 程序对于系统管理员来说是非常有用的。Cron 服务用于计划程序在特定时间(月、日、周、时、分)运行。我们以root的crontab 为例。根用户的 crontab 文件放在 /var/spool/crontab/root 中,其格式如下:
      (1)  (2)  (3)  (4)  (5)  (6)
       0   0   *   *   3   /usr/bin/updatedb
          1. 分钟 (0-60)
          2. 小时 (0-23)
          3. 日 (1-31)
          4. 月 (1-12)
          5. 星期 (1-7)
          6. 所要运行的程序
      2.Shell的功能和特点
      1>命令行解释
      2>使用保留字
      3>使用Shell元字符(通配符)
      4>可处理程序命令
      5>使用输入输出重定向和管道
      6>维护一些变量
      7>运行环境控制
      8>支持Shell编程
      对于"命令行解释"就不多说了,就是在shell提示符(例如:"$","%","#"等)后输入一行unix命令,Shell将接收用户的输入。
      "使用保留字":Shell有一些具有特殊意义的字,例如在Shell脚本中,do,done,for等字用来控制循环操作,if,then等控制条件操作。 保留字随Shell环境的不同而不同。
      "通配符":* 匹配任何位置
           ? 匹配单个字符
           [] 匹配的字符范围或列表 例如:
           
              $ls [a-c]*
             
              将列出以a-c范围内字符开头的所有文件
              $ls [a,m,t]*
             将列出以e,m或t开头的所有文件
      "程序命令" :当用户输入命令后,Shell读取环境变量$path(一般在用户自己的.profile中设置),该变量包含了命令可执行文件可能存在的目录列表。 shell从这些目录中寻找命令所对应的可执行文件,然后将该文件送给内核执行。
      "输入输出重定向及管道" :重定向的功能同DOS的重定向功能:
         ">" 重定向输出
         "<" 重定向输入
      而管道符号,是unix功能强大的一个地方,符号是一条竖线:"|",用法: command 1 | command 2 他的功能是把第一个命令command 1执行的结果作为command 2的输入传给command 2,例如:
        $ls -s|sort -nr|pg
      该命令列出当前目录中的所有文件,并把输出送给sort命令作为输入,sort命令按数字递减的顺序把ls的输出排序。然后把排序后的 内容传送给pg命令,pg命令在显示器上显示sort命令排序后的内容。
      "维护变量" :Shell可以维护一些变量。变量中存放一些数据供以后使用。用户可以用"="给变量赋值,如:
             $lookup=/usr/mydir
    该命令建立一个名为lookup的变量并给其赋值/usr/mydir,以后用户可以在命令行中使用lookup来代替/usr/mydir,例如:          
             $echo $lookup
             结果显示:/usr/mydir
             为了使变量能被子进程使用,可用exprot命令,例如:
             $lookup=/usr/mydir
             $export lookup
      "运行环境控制" :当用户登陆启动shell后,shell要为用户创建一个工作的环境,如下:
      1>当login程序激活用户shell后,将为用户建立环境变量。从/etc/profile和.profile文件中读出,在这些文件中一般都用$TERM 变量设置终端类型,用$PATH变量设置Shell寻找可执行文件的路径。
      2>从/etc/passwd文件或命令行启动shell时,用户可以给shell程序指定一些参数,例如"-x",可以在命令执行前显示该命令及其参数。后面详细介绍这些参数。
      "shell编程" :本文主要介绍的内容。
      shell本身也是一种语言(*可以先理解为unix命令的组合,加上类C的条件,循环等程序控制语句,类似dos批处理,但要强大的多),用户可以 通过shell编程(脚本,文本文件),完成特定的工作。
    SHELL变量
      下面我们详细的介绍Bourne Shell的编程:
      自从贝尔实验室设计了Bourne Shell。从那时起许多厂商根据不同的硬件平台设计了许多版本得unix。但在众多版本的unix中,Bourne Shell 一直保持一致。
      1>Bsh的启动:用户在登陆后,系统根据文件/etc/passwd中有关该用户的信息项启动Shell。例如某用户在passwd中 的信息项为:
        ice_walk:!:411:103:Imsnow ,ice_walk:/home/ice_walk:/bin/bsh
      则表明,用户名是ice_walk等信息,在最后一项"/bin/bsh"表明用户的sh环境类型是bsh,于是系统启动之。在启动或执行(包括下面我们要讲 的shell程序--脚本)过程中可以使用以下一些参数,我们一一说明:
      -a 将所有变量输出
      -c "string"从string中读取命令
      -e 使用非交互式模式
      -f 禁止shell文件名产生
      -h 定义
      -i 交互式模式
      -k 为命令的执行设置选项
      -n 读取命令但不执行
      -r 受限模式
      -s 命令从标准输入读取
      -t 执行一命令,然后退出shell
      -u 在替换时,使用未设置的变量将会出错
      -v 显示shell的输入行
      -x 跟踪模式,显示执行的命令
    许多模式可以组合起来用,您可以试试了,但-ei好象不行,你说why呢?
      使用set可以设置或取消shell的选项来改变shell环境。打开选项用"-",关闭选项用"+",多数unix允许打开或关闭a、f、e、h、k、n、 u、v和x选项。若显示Shell中已经设置的选项,执行:
        $echo $-
      Bsh中每个用户的home目录下都有一个.profile文件,可以修改该文件来修改shell环境。为了增加一个可执行文件的路径(例如/ice_walk/bin), 可以把下面代码加入.profile中
        PATH=$PATH:/ice_walk/bin;exprot PATH
       .profile中shell的环境变量意思如下:
        CDPATH 执行cd命令时使用的搜索路径
        HOME 用户的home目录
        IFS 内部的域分割符,一般为空格符、制表符、或换行符
        MAIL 指定特定文件(信箱)的路径,有UNIX邮件系统使用
        PATH 寻找命令的搜索路径(同dos的config.sys的 path)
        PS1 主命令提示符,默认是"$"
        PS2 从命令提示符,默认是">"
        TERM 使用终端类型
      2>Bsh里特殊字符及其含义
      在Bsh中有一组非字母字符。这些字符的用途分为四类:作为特殊变量名、产生文件名、数据或程序控制以及引用和逃逸字符控制。他们 可以让用户在Shell中使用最少的代码完成复杂的任务。
         *> Shell变量名使用的特殊字符
            $# 传送给命令Shell的参数序号
            $- 在Shell启动或使用set命令时提供选项
            $? 上一条命令执行后返回的值
            $$ 当前shell的进程号
            $! 上一个子进程的进程号
            $@ 所有的参数,每个都用双括号括起
            $* 所有参数,用双括号括起
            $n 位置参数值,n表示位置
            $0 当前shell名
         *>产生文件名的特殊字符
            包括"*","?","[]",上面讲过,不再多说。
         *>数据或程序控制使用的特殊字符
            >(file) 输出重定向到文件中(没有文件则创建,有则覆盖)
            >>(file) 输出重定向到文件中(没有则创建,有则追加到文件尾部)
            <(file) 输入重定向到文件
            ; 命令分割符
            | 管道符
            & 后台运行(例如:sleep 10 &)
            ` ` 命令替换,重定向一条命令的输出作为另一命令的参数
         *>对于引用或逃逸的特殊字符
      Bsh用单引号' '和双引号" "将特殊字符或由空白分隔的字引用起来组成一个简单的数据串.使用单引号和双引号的区别是双引号中的内容可进行参数和变量替换.逃逸字符也一样.
            $echo "$HOME $PATH"
             结果显示$/u/ice_walk/bin:/etc:/usr/bin
            而$echo '$HOME $PATH' 结果显示$HOME $PATH
      shell的逃逸符是一个"\",表示其后的字符不具有特殊的含义或不是shell的函数
            $echo \$HOME $PATH
            结果显$$HOME /bin:/etc:/usr/bin:
    3>Bsh的变量
      前面我们在多个地方引用了变量,当Shell遇到一个"$"符时(没有被引用或逃逸),它将认为其后为一变量。不论该变量是环境变量还是用户自定义的变量,在命令行中变量名要被变量值替换。例如命令:ls $HOME将列出变量HOME对应目录下的文件。用户可以在命令行中的任何地方进行变量替换。包括命令名本身,例如:
        $dir=ls
        $$dir f*
      将列出以f开头的文件。
      现在详细的介绍下Bsh的变量。Bsh中有四类变量:用户定义的变量、位置变量(shell参数)、预定义变量及环境变量。
      用户定义的变量:
      用户定义的变量由字母和下划线组成,并且变量名的第一个字符不能为数字(0~9)。与其他UNIX名字一样,变量名是大小写敏感的。用户可以在命令行上用"="给变量赋值,例如:
        $NAME=ice_walk
      给变量NAME赋值为ice_walk,在应用变量NAME的时候,在NAME前加"$"即可,前面已说,不再废话(别说我废话多,关键是没当过老师:()。可以用变量和其他字符组成新的字,例如:
        $SUN=sun
        $echo ${SUN}day
      在应用shell变量时候,可以在变量名字两边$后面加上{},以更加清楚的显示给shell,哪个是真正的变量,以实现字符串的合并等功能。
     
      结果显示:sunday(注意不能echo $SUNday,因为SUNday变量没定义,读者试下执行结果) 用户也可以在命令行上同时对多个变量赋值,赋值语句之间用空格分开:
        $X=x Y=y
        注意变量赋值是从右到左进行的
        $X=$Y Y=y
        X的值是y
        $X=z Y=$Z
        Y的值是空(变量未赋值时,shell不报错,而是赋值为空)
      用户可以使用"unset <变量>"命令清除给变量赋的值
      用户使用变量时要在其前面加一"$"符,使变量名被变量值所替换。Bsh可以进行变量的条件替换,即只有某种条件发生时才进行替换。替换条件放在一对大括号{}中,如:
        ${variable: -value} variable是一变量值,value是变量替换使用的默认值
        $echo Hello $UNAME
        结果显示:Hello
        $echo Hello ${UNAME: -there}
        结果显示:Hello there
        $echo $UNAME
        结果显示: (空)
        $UNAME=John
        $echo Hello ${UNAME: -there}
        结果显示:Hello John
      可以看出,变量替换时将使用命令行中定义的默认值,但变量的值并没有因此而改变。另外一种替换的方法是不但使用默认值进行替换,而且将默认值赋给该变量。其形式如下:
        ${variable:=value}
      该形式在变量替换后同时把值value符给变量variable。
        $echo Hello $UNAME
        结果显示:Hello
        $echo Hello ${UNAME:=there}
        结果显示:Hello there
        $echo $UNAME
        结果显示:there
        $UNAME=John
        $echo Hello ${UNAME:-there}
        结果显示:Hello John
      变量替换的值也可以是` `括起来的命令:
        $USERDIR={$Mydir: -`pwd`}
      第三种变量的替换方法是只有当变量已赋值时才用指定值替换形式:
        ${variable: +value}
        只有变量variable已赋值时,其值才用value替换,否则不进行任何替换,例如:
        $ERROPT=A
        $echo ${ERROPT: +"Error tracking is acitive"}
        结果显示:Error tracking is acitive
        $ERROPT=
        $echo ${ERROPT: +"Error tracking is acitive"}
        结果显示: (空)
      我们还可以使用错误检查的条件进行变量替换:
        ${variable:?message}
    当变量variable已设置时,正常替换。否则消息message将送到标准错误输出(若此替换出现在shell程序中,那么该程序将终止)。 例如:
        $UNAME=
        $echo $ {UNAME:?"UNAME HAS NOT BEEN SET"}
        结果显示:UNAME HAS NOT BEEN SET
        $UNAME=Stephanie
        $echo $ {UNAME:?"UNAME HAS NOT BEEN SET"}
        结果显示:Stephanie
        当没有指定message时,shell将显示一条默认的消息,例如:
        $UNAME=
        $echo $ {UNAME:?}
        结果显示:sh:UNAME:parameter null or not set
    4>位置变量或Shell参数
      在shell解释用户的命令时,将把命令行的第一个字作为命令,而其他的字作为参数。当命令对应的可执行文件为Shell程序时,这些参数将作为位置变量传送给该程序。第一个参数记为$1,第二个为$2....第九个为$9。其中1到9是真正的参数名,"$"符只是用来标识变量的替换。
      位置变量$0指命令对应的可执行文件名。在后面将详细介绍位置变量。
      1.只读变量
      用户将变量赋值后,为了防止以后对该变量的修改,可以用以下命令将该变量设置为只读变量:
        readonly variable
      2.export命令
      shell执行一个程序时,首先为该程序建立一个新的执行环境,称为子shell。在Bourne Shell中变量都是局部的,即他们只在创建他们的Shell中有意义。用户可以用export命令让变量被其他子Shell识别。但某用户的变量是没法让其他用户使用的。
      当用户启动一个新shell时,该shell将使用默认的提示符。因为赋给变量PS1的值只在当前shell中有效。为了让子Shell使用当前Shell中定义的提示符号,可以使用export命令:
        $PS1="Enter command:"
        Enter command:export PS1
        Enter command:sh
        Enter command:
        此时变量PS1变成了全局变量。它可以被其子Shell使用。当变量被设置成全局的以后,将一直保持有效直到用户退出该变量所在的Shell。用户可以在文件.profile中给一个变量永久赋值。详见"规范Shell"。
    基本语句
      从本节起,我们将详细介绍Shell程序设计的基本知识,通过编写Shell脚本,用户可以根据自己的需要有条件的或者重复的执行命令。通过Shell程序,可以把单个的UNIX命令组合成一个完全实用的工具,完成用户的任务。
      1>什么是Shell程序
      当用户在UNIX Shell中输入了一条复杂的命令,如:
        $ls -R /|greo myname |pg
      我们可以称用户在对Shell编程,当把这条语句写在一个文件里,并且符给该文件可执行权限,那么该文件就是我们传统上说的Shell程序。
      2>简单的Shell程序
      假设用户每天使用下述命令备份自己的数据文件:
        $cd /usr/icewalk;ls * |cpio -o > /dev/fd0
      我们可以把它写在一个文件,如:ba.sh中:
        $cat >ba.sh
        cd /usr/icewalk
        ls * |cpio -o > /dev/fd0
        ^D  (ctrl_d)
      程序ba.sh就是Shell脚本,用户可以用vi或其他编辑工具编写更复杂的脚本。
      此时用户备份文件只需要执行Shell程序ba.sh,执行时需在当前Shell中创建一个子Shell:
        $sh ba.sh
      程序sh与用户登陆时执行的Bourne Shell相同,但当Sh命令带参数ba.sh后,它将不再是一个交互式的Shell,而是直接从文件ba.sh中读取命令。
      执行ba.sh中命令的另一方法是给文件ba.sh执行权限:
        $chmod +x ba.sh
      此时,用户可以输入文件名ba.sh做为一个命令来备份自己的数据,需要注意的是,用这种方法执行命令的时候,文件ba.sh必须存在于环境变量$PATH所指定的路径上。
    3>在Shell中使用数据变量
      用户可以在Shell中使用数据变量,例如ba.sh程序:
        cd/usr/icewalk
        ls|cpio -o > /dev/fd0
      该程序中要备份的目录为一常量,即该程序只能用来备份一个目录。若在该程序中使用变量,则会使其更通用:
        workdir=$1
        cd $workdir
        ls * |cpio -o > /dev/fd0
      通过这一改变,用户可以使用程序备份变量$workdir指定的目录。例如我们要备份/home/www的内容,只要运行ba.sh /home/www即可实现。(若不明白 $1,下面将详细介绍shell参数的传递,$1代表本sh程序-ba.sh的第一个参数)
      4>在Shell程序中加上注释
      为了增加程序的可读性,我们提倡加入注释。在Shell程序中注释将以"#"号开始。当Shell解释到"#"时,会认为从"#"号起一直到该行行尾为注释。
      5>对Shell变量进行算术运算
      高级语言中变量是具有类型的,即变量将被限制为某一数据类型,如整数或字符类型。Shell变量通常按字符进行存储,为了对Shell变量进行算术运算,必须使用expr命令。
      expr命令将把一个算术表达式作为参数,通常形式如下:
        expr [数字] [操作符] [数字]
      由于Shell是按字符形式存储变量的,所以用户必须保证参加算术运算的操作数必须为数值。下面是有效的算术操作符:
        +   两个整数相加
        -   第一个数减去第二个数
        *   两整数相乘
        /   第一个整数除以第二个整数
        %   两整数相除,取余数
      例如:
        $expr 2 + 1
         结果显示:3
        $expr 5 - 3
         结果显示:2若expr的一个参数是变量,那么在表达式计算之前用变量值替换变量名。
        $int=3
        $expr $int + 4
        结果显示:7
      用户不能单纯使用"*"做乘法,若输入:
        $expr 4*5
      系统将会报错,因为Shell看到"*"将会首先进行文件名替换。正确形式为:
        $expr 4 \* 5
         结果显示:20
      多个算术表达式可以组合在一起,例如:
        $expr 5 + 7 / 3
        结果显示:7
      运算次序是先乘除后加减,若要改变运算次序,必须使用"`"号,如:
        $int=`expr 5 + 7`
        $expr $int/3
         结果显示:4
        或者:
        $expr `expr 5+7`/3
        结果显示:4
      6>向Shell程序传递参数
      一个程序可以使用两种方法获得输入数据。一是执行时使用参数。另一种方法是交互式地获得数据。vi编辑程序可以通过交互式的方法获得数据,而ls和 expr则从参数中取得数据。以上两种方法Shell程序都可以使用。在"交互式读入数据"一节中将介绍Shell程序通过交互式的方法获得参数。
      通过命令行给Shell程序传递参数可以扩大程序的用途。以前面提到的ba.sh程序为例:
      $cat >re.sh
      cd $workdir
      cpio -i < /dev/fd0
      ^d
      程序re.sh恢复了ba.sh程序备份的所有文件。若只从软盘上恢复一个指定的文件,可以用该文件名作为参数,传递给Shell程序re.sh:
      程序改写如下:
      $cat >re2.sh
      cd $workdir
      cpio -i $1 < /dev/fd0
      ^d
      用户可以指定要恢复的文件,例如fname
      $re2.sh fname
    此时文件fname作为第一个位置参数传递给re2.sh,re2.sh的缺点是要恢复两个或多个文件要重复运行,我们可以用$*变量传递不确定的参数给程序:
      $cat >re3.sh
      cd $workdir
      cpio -i $* < /dev/fd0
      ^d
      我们就可以恢复多个文件,例如fname1,fname2,fname3
      $re3.sh fname1 fname2 fname3
      (以上程序re.sh,re2.sh,re3.sh,假设用户已经chmod了可执行权利)
      因为没有赋值的变量可以作为NULL看待,所以若是程序re3.sh在执行时候没赋予参数,那么一个空值将被插入到cpio命令中。该命令将恢复所有保存的文件。
    条件判断语句
      条件判断语句是程序设计语言中十分重要的语句,该语句的含义是当某一条件满足时,执行指定的一组命令。
    1>if - then语句
      格式: if command1
         then
           command2
           command3
         fi      ---(if 语句结束)
           command4
      每个程序或命令执行结束后都有一个返回的状态,用户可以用Shell变量$?获得这一状态。if语句检查前面命令执行的返回状态,若该命令成功执行,那么在then和fi之间的命令都将被执行。在上面的命令序列中,command1和command4总要执行。若command1成功执行, command2和command3也将执行。
      请看下面程序:
        #unload -program to backup and remove files
        cd $1
        ls -a | cpio -o > /dev/mnt0
        rm *
      该程序在备份资料后,删除档案,但当cpio命令不能成功执行时,rm命令还是把资料删除了,我们可不希望这样,为了避免此情况,可以用if - then语句:
        #--卸载和判断删除程序
        cd $1
        if ls -a | cpio > /dev/mnt0
        then
          rm *
        fi
      上面程序在cpio执行成功后才删除档案
    同时,若执行没有成功,我们希望得到提示,sh中的echo命令可以向用户显示消息,并显示后换行,上面程序可以写成:
         #--卸载和判断删除程序
        cd $1
        if ls -a | cpio > /dev/mnt0
        then
          echo "正删除文件资料... ..."
          rm *
        fi
      echo命令可以使用一些特殊的逃逸字符进行格式化输出,下面是这些字符及其含义:
        \b  Backspace
        \c  显示后不换行
        \f  在终端上屏幕的开始处显示
        \n  换行
        \r  回车
        \t  制表符
        \v  垂直制表符
        \   反斜框
        \0nnn 用1,2或3位8进制整数表示一个ASCII码字符
    2>if - then - else语句
      不用多说它的作用,别的高级语言中都有,格式为:
      if command1
      then
        command2
        command3
      else
        command4
        command5
      fi
      在此结构中,command1中是先执行,当command1成功执行时,将执行command2和command3,否则执行command4和command5
      注意看下面程序:
        #备份程序
        cd $1
        if ls -a |cpio -o > /dev/mnt0
        then
          echo "删除源资料... ..."
          rm *
        else
          echo "磁带备份失败!"
        fi
    3>test命令进行条件测试
      if语句可以通过测试命令执行的返回状态来控制命令的执行,若要测试其他条件,在bsh中可以使用test命令。该命令检测某一条件,当条件为真时返回 0,否则返回非0值。test命令可以使Shell程序中的if语句象其他程序语言中的条件判断语句一样,具有很强的功能。
      test命令的使用方法为:
        test condition
      可测试的条件分为4类:
      1)测试两个字符串之间的关系。
      2)测试两个整数之间关系。
      3)测试文件是否存在或是否具有某种状态或属性。
      4)测试多个条件的与(and)或(or)组合。
    1、条件语句>>test语句
    1>测试字符串间的关系
      bsh把所有的命令行和变量都看作字符串。一些命令如expr和test可以把字符当作数字进行操作。
      同样任何数字也可以作为字符串进行操作。
      用户可以比较两个字符串相等或不等,也可以测试一个串是否赋了值。有关串的操作符如下:
        str1 = str2      当两个串有相同内容、长度时为真
        str1 != str2      当串str1和str2不等时为真
        -n str1         当串的长度大于0时为真(串非空)
        -z str1         当串的长度为0时为真(空串)
        str1           当串str1为非空时为真
      不但Shell程序可以使用test进行条件判断,test命令也可以独立执行,如:
        $str1=abcd
        $test $str1 = abcd
        $echo $?
        结果显示:0
    与上例中第一行赋值语句中的等号不同,test命令中的等号两边必须要有空格。本例test命令共有3个参数。注意两个串相等必须是长度和内容都相等。
        $str1="abcd "
        $test "$str1" = abcd
        $echo $?
        结果显示:1
      上面str1包含5个字符,其中最后一个为空格符。而test命令中的另一个串只有4个字符,所以两串不等,test返回1。
      不带任何操作符和使用-n操作符测试一个串结果是一样的,例如:
        $str1=abce
        $test $str1
        $echo $?
        结果显示:0    
        $test -n $str1
        $echo $?
        结果显示:0
      但是,上面两条命令也有一点差别,反映出了使用test命令潜在的问题,请看下例:
        $str1="   "
        $test $str1
        $echo $?
        结果显示:1
        $test -n "$str1"
        $echo $?
        结果显示:0
        $test -n $str1
        结果显示:test:argument expected
      上例中,第一次测试为假因为Shell在执行命令行之前首先要进行变量替换,即把$str1换成空格,然后shell又将命令行上的空格删除,故 test命令测试到的为空串。而在第二次测试中,变量替换后空格位于括号内,故不会被删除,test测试到的是一个包含空格的串,在第三次测试中, shell把空格删除,只把-n传个test命令,所以显示参数错。
    2>测试两个整数之间关系
      test命令与expr命令一样,也可以把字符转变成整数,然后对其操作。test命令对两个数进行比较,使用的操作符如下:
        int1 -eq int2    两数相等为真
        int1 -ne int2    两数不等为真
        int1 -gt int2    int1大于int2为真
        int1 -ge int2    int1大于等于int2为真
        int1 -lt int2    int1小于int2为真
        int1 -le int2    int1小于等于int2为真
      下面的例子反映了字符串比较与数字比较的不同:
        $str1=1234
        $str2=01234
        $test $str1 = $str2
        $echo $?
        结果显示:1
        $test $str1 -eq $str2
        $echo $?
        结果显示:0
    3>有关文件的测试
      使用test进行的第三类测试是测试文件的状态,用户可以测试文件是否存在,是否可写以及其他文件属性。下面是文件测试时使用的选项。注意只有文件存在时,才有可能为真。
      -r file     用户可读为真
      -w file     用户可写为真
      -x file     用户可执行为真
      -f file     文件为正规文件为真
      -d file     文件为目录为真
      -c file     文件为字符特殊文件为真
      -b file     文件为块特殊文件为真
      -s file     文件大小非0时为真
      -t file     当文件描述符(默认为1)指定的设备为终端时为真
    4>复杂的条件测试(and 、or 、not)
      -a         与
      -o        或
      !        非
      就是组合条件了,任何高级语言中都有的(NOT 、AND 、OR),例如:
        $test -r em.null -a -s em.null
        $echo $?
        结果显示:1
        说明了em.null并不是可读并且非空的文件
    5>另一种执行test的方法
      bsh中还有另一种执行test命令的方法,就是把测试条件放到一对[ ]中,例如:
        $int1=4
        $[ $int1 -gt 2 ]
        $echo $?
        结果显示:0
    要注意在[ 的后面和 ]符号的前面要有一个空格。
      下面我们用test命令写个简单但比较完善的程序:
        #-- 备份程序
      
        #-- 检查参数
        if [ $# -ne 1 ]
        then
          echo "请在程序名后面指出要备份文件所在目录!"
          exit 1
        fi
        #-- 检查目录名是否有效
        if [ !-d "$1" ]
        then
          echo "$1 不是一个目录!"
          exit 2
        fi
        cd $1
        ls -a | cpio -o >/dev/mnt0
        if [ $? -eq 0 ]
        then
          rm *
        else
          echo "cpio执行不成功!备份失败..."
          exit 3
        fi
    6>空命令
      在Bsh中用 : 代表空命令,就是充个数,什么都不做
    7>嵌套if语句和elif结构
      检查条件1
      A:当条件1为真,则执行一部分操作
      B:若条件1为假,检查条件2
        1)若条件2为真,执行另外一部分操作
        2)若条件2为假,检查条件3
        3)若条件3为真,执行其他一部分操作
      语法如下:
        if command
        then
          command
        else
          if command
          then
            command
          else
            if command
            then
              command
            fi
          fi
        fi
    8>elif语句
      嵌套if语句有时会给用户带来混乱,特别是什么时候fi语句很难判断。因此Bourne Shell又提供了elif语句。elif是else-if的缩写,它表示是if语句的继续。格式为:
        if command
        then
          command
        elif command
        then
          command
        elif command
        then
          command
        fi
      上面介绍的嵌套if语句和elif语句完成相同的功能,用户可以根据自己的喜好选择一种使用。
    9>case语句
      前面说的elif语句替代if-then-else语句,但有时在编程时还会遇到对同一变量进行多次的测试,该情况可以用多个elif语句实现,但还有一种更简单的方法就是用case语句。
      case语句不但取代了多个elif和then语句,还可以用变量值对多个模式进行匹配,当某个模式与变量值匹配后,其后的一系列命令将被执行,下面是case语句使用的语句。
      case value in
       pattem 1)
        command
        command;;
       pattem 2)
        command
        command;;
       ....
       pattem)
        command;
      esac
      case语句只执行其中的一组命令,当变量值与多个模式相匹配时,只有第一个匹配的模式对应的命令被执行。";;"表示该模式对应的命令部分程序。
      通过学习下面的read语句,我们们再举例子说明case语句的用法。
    10>read语句
      Shell程序不但可以通过命令行参数得到输入数据,还可以使用read命令提示用户输入数据,其语法格式为:
      read var1 var2... ...varn
    当Bsh 遇到一个read语句时,在标准输入文件中读取数据直到一个换行符。此时Shell在解释输入行时,不进行文件名或变量的替换,只是简单地删除多余的空格。然后Shell将输入行的第一个字的内容给变量1,第二个给变量2,直到所有变量都赋上值或是输入行为空。若输入行中字的个数超过变量个数, Shell将把输入行中剩余的所有字的内容都赋给最后一个变量。当变量个数多于输入行字的个数时候,多于的变量将赋一个空值。输入行的每一个字是由空格分隔的一个字母和数字组成的字符串。
      $read var1 var2 var3
        输入:Hello my friend
      
      $echo $var1 $var2 $var3
        结果显示:Hello my friend
      $echo $var2
        结果显示:my
    下面用个read和case的例子结束本部分的学习:
      #--交互式备份,恢复程序
      echo "输入要备份文件所在目录:\c"
      read WORKDIR
      if [ !-d $WORKDIR ]
      then
        echo "Sorry,$WORKDIR is not a directory"
        exit 1
      fi
      cd $WORKDIR
      echo "输入选择:"
      echo _
      echo "1.恢复到 $WORKDIR"
      echo "2.备份 $WORKDIR"
      echo "0.退出"
      echo
      echo "\c"
      read CHOICE
      case "$CHOICE" in
       1)echo "恢复中... ..."
        cpio -i < /dev/mnt0;;
       2)echo "备份中... ..."
        ls | cpio -o > /dev/mnt0;;
       0)exit 1
       *)exit 1
      esac
      if [ $? -ne 0 ]
      then
       echo "程序运行中出现错误!"
      else
       echo "操作成功!"
      fi  
     
      在上面代码中,"*"定义了其他模式下不匹配时的默认操作。
    循环语句
      前面介绍的程序和所学的语句都是从头到尾成一条主线下来,或是成分支结构,在日常管理UNIX的过程中,经常要重复的做一些操作,处理批量的问题,这就涉及到了循环结构,同高级语言相似,UNIX的Shell也提供了强大的循环处理语句。
      Bsh语言中有三种循环语句-while循环、until循环、for循环,下面通过具体的例子分别介绍这三种结构。
      While循环
      在while循环语句中,当某一条件为真时,执行指定的命令。语句的结构如下:
    while command
    do
      command
      command
      … …
    done
    示例代码如下:
    #测试while循环小程序
    x_t=1
      while [  $x_t -lt 5 ]
      do
         mm=` expr $x_t \* $int `  #注意"\"的作用
         echo "$mm"
         x_t=` expr $x_t + 1 `   #注意expr的用法
      done
      echo "THE WHILE IS END!\n"
    程序的执行结果如下:
    1
    4
    9
    16
    THE WHILE IS END
      在上述程序中,当变量x_t的值小于5的时候,执行while循环中的语句。在第五次循环时, [ $x_t-lt5]命令返回非零值,于是程序执行done后面的代码。
    现在利用while循环,可以改进我们早些时候用的备份数据的例子,当用户指定的目录备份完毕后,使用while循环使程序执行一次可以备份多个用户指定的目录。代码如下:
    echo "欢迎使用备份小程序"
      ANS=Y
      while [ $ANS = Y -o $ANS = y ]
      do
        echo _
        #读目录名
        echo "输入要备份的目录名:\c"
        read DIR
        if [ ! -d $DIR ]
        then
            echo "$DIR不是一个目录!"
            exit 1
        fi
        cd $DIR
        echo "请选择:"
        echo _
        echo "1 恢复数据到 $DIR"
        echo "2 备份$DIR的数据"
        echo
        echo "请选择:\c"
        read CHOICE
        case "$CHOICE" in
           1) echo "恢复中… …"
            cpio -i        2) echo "备份中… …"
            cpio -o >/dev/rmt0;;
           *) echo "选择无效"
        esac
        if [ $? -ne 0 ]
        then
           echo "cpio执行过程中出现问题"
           exit 2
        fi
        echo "继续别的目录吗?(Y/y)\c"
        read ANS
      done
      在程序开始,我们给变量ANS符值为Y,根据whlie的判断条件,程序进入while循环,执行do-done中的语句,每次循环都要求用户输入 ANS的值用来判断是否进行下次重复执行do-done中的语句。如果用户输入的条件不满足while语句条件,循环结束,程序执行done后面的语句。
    Until语句
      While语句中,只要某条件为真,则重复执行循环代码,until语句正好同while相反,该语句使循环代码重复执行,直到遇到某一条件为真才停止。
    Until语句的结构如下:
    until command
      do
        command
        command
        … …
      done
      可以用until语句替换上面备份程序的while语句,完成同样的功能:
    until [ $ANS != Y -a $ANS != y ]
    for 循环
      在介绍for循环之前,我们要学个非常有用的unix命令:shift。我们知道,对于位置变量或命令行参数,其个数必须是确定的,或者当Shell程序不知道其个数时,可以把所有参数一起赋值给变量$*。若用户要求Shell在不知道位置变量个数的情况下,还能逐个的把参数一一处理,也就是在$1后为 $2,在$2后面为$3等。在 shift命令执行前变量$1的值在shift命令执行后就不可用了。
    示例如下:
    #测试shift命令(x_shift.sh)
      until [ $# -eq 0 ]
      do
           echo "第一个参数为: $1 参数个数为: $#"
           shift
      done
    执行以上程序x_shift.sh:
      $./x_shift.sh 1 2 3 4
    结果显示如下:
      第一个参数为: 1 参数个数为: 3
      第一个参数为: 2 参数个数为: 2
      第一个参数为: 3 参数个数为: 1
      第一个参数为: 4 参数个数为: 0
    从上可知shift命令每执行一次,变量的个数($#)减一,而变量值提前一位,下面代码用until和shift命令计算所有命令行参数的和。
    #shift上档命令的应用(x_shift2.sh)
      if [ $# -eq 0 ]
      then
          echo "Usage:x_shift2.sh 参数"
          exit 1
      fi
      sum=0
      until [ $# -eq 0 ]
      do
          sum=`expr $sum + $1`
          shift
      done
      echo "sum is: $sum"
    执行上述程序:
      $x_shift2.sh 10 20 15
    其显示结果为:
      45
      shift命令还有另外一个重要用途,Bsh定义了9个位置变量,从$1到$9,这并不意味着用户在命令行只能使用9个参数,借助shift命令可以访问多于9个的参数。
      Shift命令一次移动参数的个数由其所带的参数指定。例如当shell程序处理完前九个命令行参数后,可以使用shift 9命令把$10移到$1。
      在熟悉了shift命令后,我们一起看看,Bsh程序中非常有用的for循环语句,这种循环同上面说的while和until循环不同,for语句中的循环是否执行并不由某个条件的真和假来决定,决定for循环是否继续的条件是参数表中是否还有未处理的参数。
    For语句的结构如下:
    for variable in arg1 arg2 … argn
    do
      command
      command
      … …
    done
    下面是for循环的简单例子:
    for LETTER in a b c d
    do
       echo $LETTER
    done
    程序执行结果如下:
    a
    b
    c
    d
    在上面计算参数和的例子中,我们可以用for循环,实现如下:
    #测试 for 程序(x_for.sh)
    if [ $# -eq 0 ]
    then
       echo "Usage:x_for.sh 参数… …"
       exit 1
    fi
    sum=0
    for I in $*
    do
       sum=`expr $sum + $I`
    done
    echo "sum is: $sum"
    中断循环指令
      在程序循环语句中,我们有时候希望遇到某中情况时候结束本次循环执行下次循环或结束这个循环,这就涉及到两条语句:continue和break。 continue命令可使程序忽略其后循环体中的其他指令,直接进行下次循环,而break命令则立刻结束循环,执行循环体后面的的语句。
    #测试continue
    I=1
    while [ $I -lt 10 ]
    do
      if [ $I -eq 3 ]
      then
        continue
      fi
      if [ $I -eq 7 ]
      then
        break
      fi
      echo "$I\c"
    done
    执行上面程序,结果如下:
    12456789
    与或结构
    使用与/或结构有条件的执行命令
      Shell程序中可以使用多种不同的方法完成相同的功能,例如until和while语句就可以完成相同的功能,同样,除了if-then-else结构可以使命令有条件的执行外,$$和||操作符也能完成上述功能。在C语言中这两个操作符分别表示逻辑与和逻辑或操作。在Bourne Shell中,用&&连接两条命令的含义只有前面一条命令成功执行了,后面的命令才会执行。
      &&操作的形式为:
        command && command
      例如语句:
        rm $TEMPDIR/* && echo "Files successfully removed"
      只有rm命令成功执行以后,才会执行echo命令。若用if-then语句实现上述功能,形式为:
        if rm $TEMPDIR/*
        then
          echo "Files successfully removed"
        fi
      相反,用||连接两条命令的含义为只有第一条命令执行失败才执行第二条命令,例如:
        rm $TEMPDIR/* || echo "File were not removed"
      上面语句的等价形式为:
        if rm $TEMPDIR/*
        then
          :
        else
          echo "Files were not removed"
        fi
      这两种操作符可以联合使用,如在下面的命令行中,只有command1和command2执行成功后,command3才会执行:
        command1 && command2 && command3
      下面的命令行表示只有command1成功执行,command2不成功执行时,才会执行command3。
      &&和||操作符可以简化命令条件执行的格式,但一般只用于一条命令的条件执行。如果许多命令都使用这两个操作符,那么整个程序的可读性将变的很差,所以在多条命令的条件执行时,最好采用可读性好的if语句。
    函数
      现在我们介绍Shell程序中的函数部分,基本上任何高级语言都支持函数这个东西,能让我们胜好多事情的东西,至少省的频繁的敲击相同的东西,好了come on
    Shell程序中的函数
      函数又叫做子程序,可以在程序中的任何地方被调用,其格式如下:
      函数名字()
      {
        command
        ... ...
        command;
      }
      Shell程序的任何地方都可以用命令 "函数名字" 调用,使用函数的好处有两点,一点是使用函数可以把一个复杂的程序化为多个模块,易于管理,符合结构化程序的设计思想,另一个好处是代码的重用。
      Shell函数和Shel程序比较相似,它们的区别在于Shell程序在子Shell中运行,而Shell函数在当前Shell中运行。因此,在当前Shell中可以看到Shell函数对变量的修改。在任何Shell中都可以定义函数,包括交互式Shell。
      例如:
        $dir() {ls -l;}
        结果是我们在$后面打dir,其显示结果同ls -l的作用是相同的。该dir函数将一直保留到用户从系统退出,或执行了如下所示的unset命令:
        $unset dir
        下面的例子说明了函数还可以接受位置参数:
        $dir(){_
        >echo "permission    ln owner   group    file sz last access
        >ls -l $*;
        >}
        运行 dir a* 看产生什么结果
        参数a*传递到dir函数中并且代替了$*
        通常Shell程序将在子Shell中执行,该程序对变量的改变只在子Shell中有效而在当前Shell中无效。"."命令可以使Shell程序在当前Shell中执行。用户可以在当前Shell中定义函数和对变量赋值。通常用下面命令来重新初使化.profile对Shell环境的设置。
        $ . .profile
      由于看到这部分相对简单,我们还是顺便说说trap好了
    使用trap命令进行例外处理
      用户编写程序在程序运行时可能会发生一些例外情况,比如执行该程序的用户按中断键或使用kill命令,或者控制终端突然与系统断开等。unix系统中的上述情况会使系统向进程发一个信号,通常情况下该信号使进程终止运行。有时侯用户希望进程在接到终止信号时进行一些特殊的操作。若进程在运行时产生一些临时文件,又因接受到的信号而终止。那么该进程产生的临时文件将保留下来。在bsh中,用户可以使用trap命令修改进程接收到终止信号时进行的默认操作。
      trap命令格式如下:
         trap command_string signals
    多数系统中共有15种发给进程的信号,默认情况下大多数信号都会使程序终止。用户最好查阅自己系统的文挡,看看本系统内使用的信号种类。除了信号为9(真正的kill信号)不能使用trap命令外,其他信号所带来的操作都可以用trap命令进行指定。下面是trap命令中经常使用的几种信号:
        信号   功能
        
         1     挂起
         2    操作中断
         15    软终止(kill信号)
      若命令串中包含不只一条命令,必须使用引号将整个命令括起来,具体是单引号还是双引号,由用户是否需要变量替换决定。" "替换,' '不替换。
      使用下面trap命令可以使程序在接收到挂起、中断或kill信号时,首先把临时文件删除,然后退出:
        trap "rm $TEMPDIR/* $$;exit" 1 2 15
      在上面例子中,当Shell读取trap命令时,首先对$TEMPDIR和$$进行变量替换,替换之后的命令串将被保存在trap表中,若上例中 trap命令使用单引号时,trap命令执行时候,不进行变量替换,而把命令串 rm $TEMPDIR/* $$;exit 放到trap表中,当检测到信号时,程序解释执行trap表中的命令串,此时进行变量替换。前面变量$TEMPDIR和$$的值为执行 trap指令时候的值,后一种情况中变量的值为程序接收到信号时候的值,所以 "、'一定要区分仔细。
      下面命令的含义为用户按二次中断键后,程序才终止:
        trap 'trap 2' 2
      一般trap命令中的命令串中几乎都包含exit语句,上面rm的例子若无exit语句,接收到信号rm命令执行完后程序将挂起。但有时用户也需要程序在接到信号后挂起,例如当终端和系统断开后,用户发出挂起信号,并执行空命令,如下:
        trap : 1
      若用户想取消前trap指令设置的命令串,可以再执行trap命令,在命令中不指定命令串表示接收到信号后进行默认的操作,命令如下:
        trap 1
    规范Shell
    获取UNIX类型的选项:
      unix有一个优点就是标准UNIX命令在执行时都具有相同的命令行格式:
      command -options parameters
      如果在执行Shell程序也采用上述格式,Bourne Shell中提供了一条获取和处理命令行选项的语句,即getopts语句。该语句的格式为:
      getopts option_string variable
      其中option_string中包含一个有效的单字符选项。若getopts命令在命令行中发现了连字符,那么它将用连字符后面的字符同 option_string相比较。若有匹配,则把变量variable的值设为该选项。若无匹配,则variable设为?。当getopts发现连字符后面没有字符,会返回一个非零的状态值。Shell程序中可以利用getopts的返回值建立一个循环。
      下面代码说明了date命令中怎么使用getopts命令处理各种选项,该程序除了完成unix的标准命令date的功能外,还增加了许多新的选项。
      #新date程序
      if [ $# -lt 1 ]
      then
        date
      else
        while getopts mdyDHMSTJjwahr OPTION
        do
          case $OPTION
          in
            m)date '+%m';;
            d)date '+%d';;
            y)date '+%y';;
            D)date '+%D';;
            H0date '+%H';;
            M)date '+%M';;
            S)date '+%S';;
            T)date '+%T';;
            j)date '+%j';;
            J)date '+%y%j';;
            w)date '+%w';;
            a)date '+%a';;
            h)date '+%h';;
            r)date '+%r';;
            \?)echo "无效的选项!$OPTION";;
          esac
        done
      fi
      有时侯选项中还带一个值,getopts命令同样也支持这一功能。这时需要在option_string中选项字母后加一个冒号。当getopts命令发现冒号后,会从命令行该选项后读取该值。若该值存在,那么将被存在一个特殊的变量OPTARG中。如果该值不存在,getopts命令将在OPTARG 中存放一个问号,并且在标准错误输出上显示一条消息。
      下面的例子,实现拷贝一个文件,并给文件赋一个新的名字。-c选项指定程序拷贝的次数,-v选项要求显示新创建文件的文件名。
      #--拷贝程序
      COPIES=1
      VERBOSE=N
      while getopts vc:OPTION
      do
        case $OPTION
        in
          c)COPIES=$OPTARG;;
          v)VERBOSE=Y;;
          \?)echo "无效参数!"
            exit 1;;
        esac
      done
      if [ $OPTIND -gt $# ]
      then
        echo "No file name specified"
         exit 2
      fi
      shift 'expr $OPTIND - 1'
      FILE=$1
      COPY=0
      while [ $COPIES -gt $COPY ]
      do
        COPY='expr $COPY + 1'
        cp $FILE $ {FILE} $ {COPY}
        if [ VERBOSE = Y }
        then
          echo ${FILE} $ {COPY}
        fi
      done

    规范Shell:
      我们知道环境变量PS1是提示符,看下面程序chdir:
      if [ ! -d "$!" ]
      then
        echo "$1 is not a directory"
        exit 1
      fi
      cd $1
      PS1="'pwd'>"
      export PS1
      我们执行:
        $chdir /usr/ice666
      结果提示符号变成/usr/ice666>了吗?没有,为什么?
      原因在于:chdir在子Shell中执行,变量PS1的修改在当前Shell中也不会起作用,若要chdir完成意想中的功能,必须在当前Shell 中执行该命令。最好的方法就是把其改成一个函数并且在.profile文件中定义。但若要把函数放到单个文件中并在当前Shell中执行,则需要使用 . 命令,并将chdir重写成一个函数,把其中的exit改写成return。下面代码是 .ice_ps的内容:
      #--提示符
      chdir()
      {
      if [ !-d "$1" ]
      then
        echo " $1 is not a directory"
        return
      fi
      cd $1
      PS1="'pwd'>"
      export PS1;
      }
      然后我们在.profile文件中加入下面语句
      .ice_ps
      然后在切换目录的时候,我们用chdir命令,结果是什么呢,自己实验好了!  
    调试Shell程序
    1>调试shell程序
      用户刚编写完Shell程序中,不可避免的会有错误,这时我们可以利用Bsh中提供的跟踪选项,该选项会显示刚刚执行的命令及参数。用户可以通过set命令打开-x选项或在启动Shell使用-x选项将Shell设置成跟踪模式。例如有下面代码ice_tx:
      if [ $# -eq 0 ]
      then
        echo "usage:sumints integer list"
        exit 1
      fi
      sum=0
      until [ $# -eq 0 ]
      do
        sum='expr $sum + $1'
        shift
      done
      echo $sum
      我们用跟踪模式运行:
      $sh -x ice_tx 2 3 4
      结果显示:
      +[ 3 -eq 0 ]
      +sum=0
      +[ 3 -eq 0 ]
      +expr 0+2
      +sum=2
      +shift
      +[ 2 -eq 0 ]
      +expr 2+3
      +sum=5
      +shift
      +[ 1 -eq 0 ]
      +expr 5+4
      +sum=9
      +[ 0 -eq 0 ]
      +echo 9
      9
      从上面可以看出,跟踪模式下Shell显示执行的每一条命令以及该命令使用的变量替换后的参数值。一些控制字如if、then、until等没显示。
    2>命令分组
      Shell中若干命令可以组成一个单元一起执行。为了标识一组命令,这些命令必须放到"()"或"{}"中。放在"()"中的命令将在子Shell中运行,而放在"{}"中的命令将在当前Shell中运行。子Shell中运行的命令不影响当前Shell的变量。当前Shell中运行的命令影响当前 Shell的变量。
      $NUMBER=2
      $(A=2;B=2;NUMBER='expr $A+$B';echo $NUMBER)
      结果为:4
      $echo $NUMBER
      结果为:2
      如果把上面的()变成{},结果会是怎么样的呢?
    3>使用Shell分层管理器shl
      UNIX是一个多道程序设计的操作系统,一些UNIX系统利用这一特性提供了Shell层次管理器shl。使用shl用户一次可以打开多个层次的Shell,其中活跃的Shell可以从终端上获得输入。但所有Shell的输出都可在终端上显示,除非显示被禁止。
      多个Shell中有一个为shl,当用户在某个Shell中工作时,可以通过使用特殊字符(一般为Ctrl+z)返回shl。为了同其他Shell区别,shl中提示符为">>>"。当用户工作在Shell层次管理器中时,可以创建、激活和删除Shell,下面是shl中使用的命令。
      create name    产生名为name的层次
      delete name    删除名为name的层次
      block name     禁止名为name的层次的输出
      unblock name    恢复名为name的层次的输出
      resume name    激活名为name的层次
      toggle       激活近来经常使用的层次
      name        激活名为name的层次
      layers [-l] name  对于表中的每个层次,显示其正在运行的进程的进程号,-l选项要求显示详细信息。
      help        显示shl命令的帮助信息
      quit        退出shl以及所有被激活的层次

    总结
      在前面我们主要介绍了sh的变量、基本语法、程序设计等。如果掌握了这些内容,在学习其他UNIX下编程语言的时候,相信有一定的好处,我们说了,在大多数的UNIX中都提供Bourn Shell,而且很少有象sh这样强大的脚本编辑语言了,是系统管理员和程序员的一笔财富,并且不需要额外的软件环境,对文件等处理借助unix命令,实现起来比c实现还要简单。

Open Toolbar