2009年5月4日星期一

透过共和国六十年货币存量史,试分析中国经济发展本质

货币存量又称为货币供应量,是全社会在某一时点承担流通手段和支付手段的货币总额,它主要包括机关团体、企事业单位和城乡居民所拥有的现金和金融机构的存款等各种金融资产。货币供应的数量、流动性状况是社会总需求变化的货币表现,是各国的主要经济统计指标之一,也是中央银行执行货币政策的重要依据。我国现阶段货币供应量的统计数据主要从银行概览中加工整理后取得。货币供应量一般根据货币流动性的差距分层次统计。我国的货币供应量按流动性由强到弱,分为M0、M1、M2三个层次:M0——流通中的现金,即央行历年货币发行总额;M1——M0+活期存款,亦称为"狭义货币供应量";M2——M1+定期存款+货币市场共同帐户++其他存款(财政存款除外),亦称为"广义货币使应量"。

我国有货币存量统计数据的资料始于1952 年,当年的货币存量(M2)101.3亿元,请大家记住这个数字。从52年到57年,M2基本上是以每年12-15亿元的速度增加,货币增长保持在10%左右,57年达到197.7亿元,这是比较正常的速度;从58年开始就不对了,货币增长也开始大跃进,以每年平均25%的速度猛增,导致建国后的第一次通货膨胀。从61年到64年,三年自然灾害,第一次出现通货紧缩,M2由1961年的439.8亿元降到1964年的434.7亿元,降幅并不大,但是比较好的度过了自然灾害期,国民经济有所恢复。65年到68年又开始了第二次冒进,每年平均新增货币56亿,每年增长速度为14%,68年达到666.9亿元。69年到70年"调整,巩固,提高",出现第二次通货紧缩,每年货币减幅只有7亿元。

从70年到79年开始了第三次温和的通货膨胀,每年平均新增货币90多亿元,增长速度是15%左右,增长量保持在百亿元之内,增长速度控制在20%以内。1952年到1979年都可以称为"高增长低通胀"经济发展期。

81年到83年开始进入改革开放,新增货币增长量上了新台阶,每年平均新增货币400多亿元,货币增长速度为22%,也还算正常;从84年到89年突飞猛进,每年平均新增货币1500多亿元,89年货币存量达到12000亿元,第四次通货膨胀可以称为奔驰的通货膨胀。

从90年到93年,货币增长量每年都还控制在数千亿元之内,没有超过万亿元:90年与89年相比,新增5253亿元,91年比90年新增4100亿元,92年比91年新增6100亿元,93年比92年新增9400亿元,环比增长速度39%!93年货币存量达到34879亿元。
94年开始货币增长量超过万亿:94年比93年新增12100亿元,环比增长速度为34.6%;95年比94年新增14000亿元,96年比95年新增16000亿元,97年比96年新增15000亿元,98年比97年新增13500亿元,99年比98年新增15400亿元,2000年比99年新增15600亿元,2001年比2000年新增18200亿元,货币存量达到152888亿元。平均年增长量为15100亿元,平均增长速度在39%左右,可以称为第五次通货膨胀期。
2002年更不得了,货币增长量开始突破三万亿:2002年比2001年新增31000亿,2003年比2002年新增36000亿元,2004年比2003年新增34000亿元,货币存量达到253207亿元。增长量加大了而同期的货币增长速度却降了下来:年平均增长速度在33.3%。这一阶段,我们可以称为"第六次比较平稳的通货膨胀期"。

中国实际货币供给量大大高于理论上的货币供应量。大家知道,改革开放以来我们的经济平均增长速度为10%,而货币存量平均增长速度是31.5%,个别年份的甚至超过40%!也就是说,我国改革开放以来货币贬值速度在20%以上!一部新中国经济发展史,实际上就是一部隐蔽的通货膨胀史。为什么说是隐蔽的?这是由于在集中计划经济体制下,由于存在着严格的价格管制,价格上升趋势的真实程度被隐蔽了。经济体制转制后这个影响仍然存在。既然通货膨胀这么厉害,为什么没有引起金融崩溃和经济生活混乱呢?其一,这是由于建国时货币存量基数本身太低,除了两次通货紧缩外,80年代之前每年增加的货币量还不能适应现实的货币需要,因而长期保持了低流通、低物价;其二,经济持续快速的增长时期也需要大量流通货币的支撑,再加上我国信用制度不健全使现金需求量更大;其三,我们更受益于强大的集中的行政管理体制和长期的计划经济影响,政治和政体的稳定有力地保证了经济和金融的稳定。
下面我们再从货币数量方程式中推导出为什么会产生比较高的通货膨胀率以及高通货膨胀率没有发生经济混乱。
货币数量方程式:MSV = PY d
其中,MS——代表一国的货币供给;V ——代表货币流通速度;
P ——代表总体价格水平;Y d——代表真实总需求。那么, PY d
就代表了需要交易的商品总额,一定时期内PY
d是个确定数字。80年代之前由于交易通信技术的落后,我国的货币流通速度非常低,因而需要比较大的货币供给;80年代之后技术是跟上去了,但是信用降下来了,仍然需要比较高货币供给。这就是为什么比较高的通货膨胀率没有严重影响社会政治经济的原因之一。
如果我们还想寻找更多原因的话,20世纪80年代中后期,我国有大量的货币资金积聚在我国不成熟的资本市场上,众多的货币持有者试图在不完备的资本市场上攫取自己的第一桶金(2003,伍志文,货币虚拟化过程中的"资本市场货币积聚假说",《经济学(季刊)》2003年10月);

房地产市场的成熟与活跃也吸引了相当部分的资金。事实上我国的"超额"货币供给自80年代以来就一直存在并呈加速趋势,让好多人担心这个"笼中虎"随时都可能跑出来危害商品市场并引起急剧的通货膨胀,但是没有,反而在2004年、2005年出现了通货紧缩的态势,造成人民币升值的压力(升值的另一个重要原因是来自国际社会的压力)。

从另一方面讲,由于过去多年来固定资产投资的大幅增长,导致当前产能过剩,产能过剩领域也由消费品领域扩展至生产资料部门的加工工业和原材料工业三个产业链环节。在产能过剩因素约束下,近期也不可能发生急剧的通货膨胀。
最后我们还应该感谢中央银行的货币专家们,他们的敬业和高超的调控技术(公开市场活动、法定准备金率、贴现率)抑制了通货膨胀,保证了我国社会经济的平稳发展和金融秩序的稳定。

始于房价快速上涨的这一轮通货膨胀的根本原因已经一目了然——货币供应量的疯狂上涨。到2007年3月,货币供应总量已达到惊人的36万4100亿元。改革开放以来我们的经济平均增长速度为10%,而货币存量平均增长速度是31.5%.

弗里德曼说通货膨胀的唯一原因来自印刷厂,每次通货膨胀都与货币增加有关,只要货币数量的增加快于产量的增长,通货膨胀就会如期而至,两者的时滞约为15—24个月。其实现在的CPI数据都没有包含资本市场和房地产市场,如果把这两点包括进去,依然符合。但是现在政府为了不让人民币升值只能再拼命的往市场上砸钱抵销日益巨大的贸易顺差。

扣除增加的1万亿美元外汇而发行的82000亿人民币,现在与2001年底相比,货币供应量增加了13万亿~14万亿,而2001年年底的货币供应量是15.83万亿,也就是说在去除外汇因素下,从2002年到现在货币供应量还是翻了近一倍。

再来看看这几年的财政收入,2002年18904亿元,2003年21715亿元,2004年26355.88亿元,2005年31649.29亿元,2006年39373.2亿元,2007年1-5月21723.53亿元。

货币供应量按流动性划分为 M0、M1、M2、M3四个层次;

现阶段我国货币供应量划分为以下三个层次:

M0 --流通中的现金

M1 -- M0 +企业单位活期存款+机关团体部队存款+农村存款 ;

M2 -- M1+企业单位定期存款+自筹基本建设存款+个人储蓄存款+其他存款。

M1 是狭义货币供应量, M2 是广义货币供应量; M1 与 M2 之差是准货币。
货币层次的划分:世界各国对货币供应量的统计口径有狭义和广义之分,以便中央银行控制有所侧重,具体为:

M0=现金(通货)

M1=M0+商业银行的活期存款

M2=M1+商业银行的定期存款(包括定期储蓄存款)

M3=M2+其他金融机构的存款

M4=M3+大额可转让定期存单(CDs)

M5=M4+政府短期债券和储蓄券

M6=M5+短期商业票据

其中,对M1到M3的监测和调节被大多数国家的中央银行所采用,比如美国联邦储备体系最看重M2,英格兰银行则注意M3,而日本银行强调的是M2+CDs。

毫无疑问,我们是模仿国外的所谓现代银行管理、统计体系设立的M系统。但我们多年了的M系统仅仅是模仿,而没有实际经济意义。

比如,中美两国的M系统,若M1数值相同,则美国的有实际经济意义的现钞就是M1,而中国有实际经济意义的现钞则要远远小于M1。这个差别使中国经济单位没有足够的流通货币,而美国相对于中国则有充裕的货币。

造成这个差别的原因在于,中国的支票不能直接兑换成现钞,尽管它是货币。

再比如在M2项目下,若M2相同,则中国的储蓄额很大,但流通的、有实际经济意义的货币却很少,因为中国的M2被高额储蓄占掉了,而美国却几乎全部是M1(美国储蓄率很低)实际也就是全是M0,即决大部分是现钞,市场有经济意义的货币充足。而中国却是市场严重缺少有实际经济意义的货币。

这就是为什么美国一直倾向于使用M2来调控货币的原因。

中国金融界无论是理论家还是主管部分一直有一个非常固执和愚蠢的见解,认为美国人不储蓄。其实这是一种错误的见解,美国人也是人、也需要穿衣、吃饭、养老等支付,这些支付同样需要持有货币存量,那么为什么美国的储蓄率很低呢?其实既不是美国人不储蓄,也不是美国人没有钱,而是这些货币存量不在储蓄项目下,而是在支票项目下,即在M1项目下。

因此,同样的M2、M1、M0水准,美国的M体系有大量的具有实际经济学意义的货币,而中国则是严重货币短缺。

如果中国金融改革仅仅改变这个M系统,则中国实际有经济学意义的货币就将增加十万亿以上(储蓄转成支票,支票可自由兑换现钞),而货币总量却不需要任何改变。
另外一个方面,美国及西方国家设立M系统是为了便于统计和调控印钞数量及观测经济动向。其中支票有大额和一般额度,这才是区分M1和M2的关键,也就是说有多少交易是以大额交易的、有多少交易是以一般额度交易的。大额交易主要发生在大型公司之间和投资****易。

正如前文所述,无论M1、M2,由于支票的自由兑换性,二者都有实际的经济学意义。在货币总量上意义相同,但在资金用途上却有重要的经济学意义。货币总量以M1出现,则消费和终端市场活跃;以M2出现,则投资和中间市场活跃。

美联储和各商业银行可以据此判定应如何判定货币政策。M2过高而M1过低,表明投资过热、需求不旺,有危机风险;M1过高M2过低,表明需求强劲、投资不足,有涨价风险。在货币总量则基本保持稳定。

资料来源:
1、《中国经济年鉴》2000,2001,2002,2003,2004,2005
2、《中国货币市场年鉴》2000,2001,2002,2003,2004
3、赵留彦、王一鸣《货币存量与价格水平:中国的经验证据》(北京大学经济学院)

佚名者后记解析:

如果汇率能抗住的话,未来3年中国将率先走出危机,楼市还会翻番,股市会上1万点。推升楼,股的货币供应的绝对充足的,就看M2游戏还可以玩儿多久了。按照M2的年均增速,如果还能在玩儿10年的话,楼市就会在涨3-5倍,股市会上3-5万点,哈哈~!

看看头些日子动辄给军队加薪50%以上,还有庞大的公务员队伍,行政开支,M2未来只能更快,很难慢下来。未来10年,美元储备想在按照过去10年一样,成几何数字暴涨是不可能的了,美国的消费能力已经达到极限了。

我国有货币存量统计数据的资料始于1952 年,当年的货币存量(M2)101.3亿元,请大家记住这个数字。截止到今年M2已经高达53万亿了,也就说说57年来,M2年均复利增长16.2%。过去的年景,通缩的时候,M2还会负增长,现在可倒好,通缩,M2更有借口大幅增长了。
美国过去100年的年均通胀率不过3%,知道美元为甚麽是世界货币了吧~!也知道RMB不可能成为世界货币了吧~!还国际化,真能吹啊~!呵呵。基本上都是M2先超长增长,20%以上,之后1-3年内出现大通胀。通过历史资料可以知道,M2反应到物价上有一个迟滞效应。另外,物质紧缺,会给通胀再来个加速度。建议大家提前布局,要么买资源,要么持有美元,今年年中开始,就可能突然发生一夜通胀。整个共和国史,基本上就是一部大通胀史。美元黄金换了,要藏起来,千万别曝露,否则招灾。

从90年到93年,货币增长量每年都还控制在数千亿元之内,没有超过万亿元:90年与89年相比,新增5253亿元,91年比90年新增4100亿元,92年比91年新增6100亿元,93年比92年新增9400亿元,环比增长速度39%!93年货币存量达到34879亿元。93-96的超级大通胀,是90-93年打下的基础,环比增速39%,这三年, 也是海南房地产投机热发展到顶点的时候。

94年开始货币增长量超过万亿:94年比93年新增12100亿元,环比增长速度为34.6%;95年比94年新增14000亿元,96年比95年新增16000亿元,其实97年之后,如果没有美元输入的话,天朝就会步入津巴布韦的境地了。那么今日津巴布韦的记录,本来应该是天朝来打破的。没有美元支撑RMB的信用,RMB早崩盘了。

97年比96年新增15000亿元,98年比97年新增13500亿元,99年比98年新增15400亿元,2000年比99年新增15600亿元,2001年比2000年新增18200亿元,货币存量达到152888亿元。平均年增长量为15100亿元,平均增长速度在39%左右,可以称为第五次通货膨胀期。看看M2吧,从来就没慢过。

89年底M2存量不过1.2万亿,今年3月份是54万亿,也就说20年来年均增长M2,21%幸亏天朝有美元输血,和10几亿P民,否则你我今日,过的不会比津巴布韦好到哪去的~!年均21%的M2增速,中国永远不会产生中产阶级的。产生了,3-5年内就会被通胀掠夺一空。

lijiejun168博友的跟贴评论:

但斌:昨夜招行发布了一季报,许多持有招行的朋友可能崩溃了,为此我在东方财富老股民博客处发表了一些个人观点,现转发给您。
我把我今晚上的几段发言整理一下:(一)截至2009年3月末,(招行)本公司贷款及垫款总额为9,527.16亿元,比年初增长14.30%,其中,公司贷款占比56.85%,零售贷款占比24.64%,票据贴现占比18.51%。客户存款总额为13,716.66亿元,比年初增长16.42%。实际贷款总额为9527.16×81.49%=7763.68亿元。
截至2008年12月末,(招行)本公司贷款及垫款总额为8335.48亿元,其中,公司贷款占比62.20%,零售贷款占比26.31%,票据贴现占比11.49%。实际贷款总额为8335.48×88.51%=7377.82亿元。
(二)招行一季度太过保守,以公司而不以集团来看:2008年4季度公司发放贷款总额为7377.82亿(剔除垫款,也就是大家通俗讲的票据贴现),存款为11782.40亿,存贷比为62.61%;2009年一季度贷款额为7763.68亿,存款为13716.66亿,环比新增贷款5.23%,环比新增存款16.42%,存贷比为56.60%。贷款增长速度在业内最为缓慢,但存款增长却非常快。
(三)我尊敬的老股民,上述所有数据都是在招行业绩报告中找出来的,其中摘录的2008年年报数据在招行年报的电子版第33页可以查到,如果您核实了数据就对会招行有新的评价,更何况环比2008年4季度的20亿净利润,一季度的42亿净利润是不是有了长足的进步呢?我刚读到招行一季报时被结果吓得半死,后细细看过并多方比较后,心情才平复下来。
(四)招行在息差大幅收窄的情况下,并没有如其他行一样快速扩大信贷规模,再加上存款快速增加,所以表现为收入大幅减少,净利润下降较大,所以以何种心态解析一季度银行季报,看来是众口难调。在某种程度上,我觉得从长期价值投资角度看招行,反而更有价值。大家在招行季报看看,永隆一季度存贷比51.99%,真是保守到极点。现在大力扩大信贷规模的其他银行,未必今后会走得更远。这是我回答我尊敬的老股民对招行看法的一些回复。
(五)我常来你地盘坐坐,但几乎不发言。只是去年以ljjtt8注册名发过一篇短文,内容是从商业连锁的角度看银行,非常喜欢你,但我属于那种在一边静静欣赏人的那一小撮人。
(六)兴业:08年末存款余额6324.26亿元,贷款余额(剔除贴现后的)4418.57亿元,存贷比为69.87%;09年1季度末存款余额7274.59亿元,贷款余额5182.99亿元,存贷比为71.25%;09年1季度末环比增长:存款余额15.03%,贷款余额17.30%,存贷比提高1.38个百分点。
民生:08年末存款余额7857.86亿元,贷款余额(剔除贴现后的)5944.29亿元,存贷比为75.65%;09年1季度末存款余额9242.60亿元,贷款余额6630.35亿元,存贷比为71.73%;09年1季度末环比增长:存款余额17.62%,贷款余额11.54%,存贷比下降3.92个百分点。
(七)浦发:08年末存款余额9472.94亿元,贷款余额(剔除贴现后的)6715.13亿元,存贷比为70.89%;09年1季度末存款余额10853.67亿元,贷款余额7553.56亿元,存贷比为69.59%;09年1季度末环比增长:存款余额14.58%,贷款余额12.49%,存贷比下降1.30个百分点。
招商:08年末存款余额11782.08亿元,贷款余额(剔除贴现后的)7377.82亿元,存贷比为62.61%;09年1季度末存款余额13716.66亿元,贷款余额7763.68亿元,存贷比为56.60%;09年1季度末环比增长:存款余额16.42%,贷款余额5.23%,存贷比下降6.01个百分点。
特别一提的是:浦发和招商09年1季度末的贷款余额几乎相等,但存款余额浦发少招商几乎3000亿元。
(八)粗粗的对比一下浦发和招商09年1季度末经营数据很有意思。在两家银行发放贷款数额相差不多,但招行却要为多于浦发的将近3000亿元的存款支付利息的情况下,净利息收入招行录得94.81亿元、浦发录得72.23亿元;最终本季度招行录得净利润42.08亿元,浦发29.60亿元,在经营能力上招行还是明显胜于浦发。

SUN和思科:命运迥异

  上一次经济周期低潮时刻的不同应对,如何让两家传奇公司的命运迥异。

  如果你经常感慨于科技公司的估值窜升之快,请看这样两家公司的命运变换:在2000年以前的互联网浪潮中,它们都是备受资本市场追捧的明星,市值分别达到5300亿美元和2000亿美元,而在网络泡沫破碎后,它们的股价均一落千丈,并展开各自历史上首度裁员。9年时间过去了,又经历了一次经济周期的轮回,它们的现状是:一家公司较网络泡沫高潮时收入翻了一倍,即使经济危机让其市值打了对折,仍维持在1000亿美元档次,并拥有近300亿美元现金;另一家也有着130亿美元的收入规模,但在被收购传闻之前,其市值仅有30亿美元。

  这两家位势悬殊的公司你并不陌生:前者是网络设备巨头思科(Cisco
Systems),后者则是曾自称为".com那个点"的升阳微系统(Sun
Microsystems)。当几乎全世界对于科技领域的关注都被聚焦于Facebook、Twitter等后起之秀,这些成立于1980年代的老玩家们最近重新成为了话题中心:IBM据说将以70亿美元之价收购江河日下的升阳,而思科则于近期宣布进军服务器市场,且以5.9亿美元价格收购了针对年轻人的数码摄像设备公司Pure
Digital。

  且不论IBM的收购能否达成,思科的新扩张是否奏效。一个值得探究的问题显而易见:什么让思科和升阳这两家曾经犹如双胞胎的公司—它们均诞生于硅谷,均在激烈竞争中成为某一重要市场的霸主,均在科网泡沫期间高度依赖一两类核心产品,也均拥有极富领袖魅力的CEO—在短短几年间有了天渊之别?

  并不容易简单做出对比。思科和升阳毕竟处于不同市场,而在过去一个周期中,这两个市场的变化力度有所不同。但辩证地说,市场格局是否会发生天翻地覆的变化,一定程度上也与行业领导者的应对能力有关:仅从结果看,思科没有被Juniper甚至华为们颠覆,但升阳却成为了英特尔、IBM、微软和开源软件们瓜分的盘中餐—根本言之,还是这两家公司领导者在网络泡沫破碎这一巨大挫折后对产业中长期变化的判断,以及公司内推行变革的力度决定的。

  它们所拥有的共同命运是,纳斯达克的崩盘并非网络需求的终结。在2000年时,互联网仍以文字为主,所有人都清楚,海量的图片、声音和视频将让网络基础设施的需求跃升。

  但一个隐性的变化是,在网络业井喷时期,思科和升阳受益于它们的品牌:所有轻易融资的网络公司都不吝成本购买贴有它们品牌的产品,正如1970年代时人们常说的,"没有人因为采购IBM的产品而被解雇",在1990年代,没有人因为采购升阳/思科而被解雇。

  这曾经意味着高昂的利润,但此后却变成了一个心理陷阱:你究竟认为高昂的利润来自于你的产品的优异性能,还是品牌?

  时任升阳CEO的斯科特·麦克尼利(Scott
McNealy)的答案倾向于前者。这位在硅谷因巧舌如簧而闻名的传奇创始人太过自信于公司的技术,以至于2001年底当他公开嘲笑微软的.Net战略为.Not战略,将IBM的Regatta服务器称为"Regratta"(意为"后悔")时,他严重低估了自己已卷入了几方势力中间,而这攸关公司生死:IBM和惠普们借助自己的咨询业务销售越来越多的高端服务器,这直接构成了对升阳产品的竞争;而微软、戴尔们也看重此一市场,以相对低价的产品切入其中;另一个不可忽视的力量是开源操作系统Linux,虽然它的产品并不可能像其它对手们一样性能强大,但它的优势同样明显,即成本极低。

  的确,麦克尼利有其自信的资本。作为硅谷最创新的公司之一,它独创的SPARC架构的芯片和Solaris操作系统的结合,令其在硬件、软件方面都有相当的技术优势。但或许也正因为其产品优异,它忽视了一个根本问题:在企业级市场上,功能的提升并非唯一考量因素,当网络狂潮不复,人们越发在意性价比这一指标。而且,摩尔定律本身就意味着,那些曾经不值一哂的对手们,比如Linux或微软、戴尔推出的低端PC服务器,能够以18个月性能翻倍的速度进化,直到它们与升阳产品的功能不再有本质差别。

  对于同样的问题,思科却心知肚明—这并非它比升阳更清醒,而是它及早的、结结实实的接受了现实的教育。

  网络泡沫后,思科试图扩宽自己的市场,并先后进入了企业电话系统、针对个人用户的网络及电话设备,以及为电信运营商提供价值数百万美元的路由器。在这些领域,客户不再像当年的网络公司一样迷信思科这一品牌。比如,当它向当时的美林证券推销自己的电话系统时出了差错,干脆丢了合同,因为美林完全不能接受自己的交易员们在买卖股票时电话拨不通。异常挑剔的新市场环境下,思科一度饱受挫折:在企业级电话业务上,北电和物美价廉的Avaya公司让它饱尝痛苦;在家庭市场,摩托罗拉、西门子和汤姆逊更知道如何服务于普通消费者;甚至在大规模、高速路由器领域,后起之秀Juniper也让思科一度自愧不如。

  种种遭遇让思科一度变得谦卑:在2000年之前曾宣称公司市值可望达到一万亿美元、并对传统电信公司们颇有不敬的公司CEO约翰·钱伯斯(John
Chambers)在很多公开场合对电信公司们致以歉意。而在内部,思科培养着针对不同市场的新鲜技能,包括适时收购Linksys、科学亚特兰大等在家用产品市场有长期积累的公司,历时四年投资五亿美元于可以与Juniper的高端服务器竞争的CSR产品线,并在统一通讯、视频系统、网络安全等领域逐步扩张。到2008年底,它在路由器和交换机这两大传统支柱业务之外的收入已经达到了120亿美元,约等于在几年间培养出一家规模与升阳相当的公司。

  比起思科"知耻后勇"式的成长,升阳当初的自信满满就显得有些短视。它所在的企业应用市场,可以被细分为操作系统+服务器、中间件、数据库、应用软件、软件实施等很多领域,当其竞争对手如IBM、惠普、微软、甲骨文们纷纷跨越疆界扩张时,太执着于与微软针锋相对的升阳越发变成了一个边缘玩家。归根到底,这是一个科技业最经久不衰的话题:如何面对周期性的行业革命?科技业的发展并非持续的改进,而是每隔一个阶段进入一个平台期,弱小玩家在此阶段与领先者缩小差距,甚至孕育颠覆式发展。英特尔在小型机发展进入平台期时展开了持续不断的追击,上网本在摩尔定律失效时成为了笔记本产业的价格杀手,而升阳则在这样一个缺乏突破性创新的时期被以英特尔和Linux为主的低端服务器赶超。这也正是是公司CEO最需要展现洞见力与勇气的时候。

  这不免让人想起曾为王安电脑工作的钱伯斯对早年工作经历的一个总结:"任何人都不可能预测市场的变化。在王安电脑,我们进行了四次转型,但第五次时即小型机转向个人电脑及软件时失败了。如果你不能永远跟上市场变化,你就被淘汰了。"

SUN浮沉路:只有技术不能长久成功

现在,这轮"红日"的确有些"日薄西山"。

在2000年9月,SUN
太阳微系统的股价曾达到历史最高点258.75美元,市值2000亿美元。2008年11月24日则探底至2.59美元,市值20亿美元。八年间,太阳微系统的股价相差百倍。

这还没有结束太阳微系统的厄运。金融、电信这些高质量客户一直让太阳微系统引以为豪,但2008年开始的金融危机将这些高质量客户横扫一遍。太阳微系统的日子难以为继,成为IT领域的重灾区。

2000年以前,太阳微系统似乎一直很走运。1982年太阳微系统在斯坦福大学诞生。两年后创始人之一、骄傲且尖刻的"疯子"斯科特·麦克利尼成为CEO,这个CEO连任22年。4年后,这个"疯子"带领太阳微系统登上纳斯达克。6年后,太阳微系统做到10亿美元规模。11年后,太阳微系统便成功晋升世界财富500强。

更辉煌的在后面。1995年,太阳微系统发布JAVA编程语言,风靡全球,至今依旧是一项非常成功的技术,在IT业留下不可磨灭的历史。

然后,在2000年,互联网风行的时候,大量互联网新贵的奢华订单将太阳微系统推向顶峰。

2000年,在太阳微系统最美的日子里,多方面的声音向太阳微系统发出善意的提醒:你的客户群过于单一、风险极大。麦克利尼一点都没听进去这样的劝告。在互联网泡沫破灭的时候,毫无准备的太阳微系统受到重创,再无机会重振雄风。

太阳微系统除了客户群单一,在技术思路上也一度坚持"独有",从芯片到操作系统,中间件、存储软件,再到服务器硬件,太阳微系统无所不做,这种"独有"在保持独立风格和技术的先进性同时,其实也是一种封闭。

在太阳微系统被光芒笼罩的日子里,英特尔的低端芯片还毫无作为。但英特尔按照摩尔定律演进着自己的速度,而太阳微系统则沉醉于自己的技术之中。很快,英特尔芯片的性能已经赶上太阳微系统,价格却低出很多。英特尔的芯片可以嵌入所有除太阳微系统之外的服务器中,拥有与业界广泛的合作。英特尔迎头追上之后,太阳微系统所垄断的高端服务器市场就不断被侵蚀。骄傲的太阳微系统一度不愿面对现实,后来不得不接受英特尔的X86架构,太阳微系统还能拥有一丝优势的高端服务器市场不断被X86架构挤压。

在操作系统领域的竞争也是一样,太阳微系统自己一直延用自己独特的操作系统,开发复杂的操作系统——有时是一门"高精尖"的工程学,需要求助于贝尔实验室——成为一个更为直接的工程学任务。而微软借助Windows
NT朝着成熟迈进,微软进入企业市场并不一帆风顺,但借助与业界的广泛合作,逐渐缩短差距,并慢慢成为主流。随后,开源的LINUX软件也逐渐势强,虽然与太阳微系统的Unix同属开源阵营,却毫不留情地分食了太阳微系统的领地。

在微软宣传自己的平台商业模式的那段日子里,太阳微系统一直在不断推崇自己先进的技术与产品。在微软建立自己生态系统的时候,太阳微系统一直在独乐乐地攻击着自己的每一个竞争对手。你会发现,很多企业都将微软视为竞争对手,但都不会排斥与微软的合作,包括甲骨文和IBM。但太阳微系统把每一个
IT巨头都看做对手,并且拒绝与之合作。在技术界赢得了尊敬,却没有在商业界建立人脉,几乎同微软比尔·盖茨、苹果乔布斯同时出道的麦克利尼在业界被称为疯子和孤独的牛仔。虽然,太阳微系统的后期有所改变,接受了英特尔,接受了微软,但做得太晚,而且无法改变太阳微系统骨子里的孤傲。

在与英特尔的较量中失守芯片,在与微软、LINUX的较量中失守操作系统,在与甲骨文、IBM、BEA的较量中失守中间件,在与EMC、惠普以及赛门铁克的较量中失守存储市场。

太阳微系统在麦克利尼20多年的掌控下"性格"也变得固执。一方面自我陶醉,另一方面又英勇好斗,与每一个IT巨头斗狠。在自恋与仇视中,麦克利尼和太阳微系统忽略了业界的潮流。

太阳微系统后期治好了"自闭症",敞开怀抱,但又一下子开放过度。开源似乎是行业的趋势,但所有开源的厂商都没有想好商业模式的问题。所以,IBM、甲骨文虽然是开源的拥趸者,但他们却使终没有把自己最赚钱的软件拿出来开源。一向崇尚技术、崇尚自由的太阳微系统却一发不可收拾,把自己的家当一股脑地都双手送了出去。太阳微系统的开源赢得了行业的尊敬,也进一步将微软推向霸权的孤峰。但微软依旧赚着自己的钱,而太阳微系统的日子却越来越难过。以至于业界都在怀疑,太阳微系统是不是为了与微软斗气而使出的小性子?

当然,太阳微系统的大奉送行动并不单纯,一向不擅长制定商业战略的太阳微系统是想以与众不同的形式赢得用户。它以为把"好吃"的软件免费送给用户,希望用户为同样"好吃"的硬件多付一点钱。太阳微系统的算盘没有成功,用户并不买账。

很多人将太阳微系统的成功归结为技术的成功,而太阳微系统的失败是商业路线的失败。它的成功有一些偶然的因素,但它的今天却是战略选择的必然。太阳微系统的故事再次证明,只有技术的公司并不能长久地成功。

双buffer与单buffer

在嵌入式平台Linux,主要通过framebuffer来显示UI。FrameBuffer实际上就是嵌入式系统中专门为GPU所保留的一块连续的物理内存,LED通过专门的总线从framebuffer读取数据,显示到屏幕上。
根据系统中framebuffer的数量,可以分成单buffer和双buffer两种。
先来说说单buffer:
CPU往framebuffer上写,LED从framebuffer读,这是两个同时进行的过程,需要在时间上配合,否则会出现问题。
如果CPU往framebuffer上写的速度>LED从framebuffer读的速度,那么就有可能出现LED在一行一行的读取前一屏数据的时候,CPU却已经刷新了整屏,从而导致显示混乱。这里要注意,LED从framebuffer读的速度并不等于屏幕的刷新频率,如果刷新频率为60hz,那么很有可能LED花了3个ms去读,剩余的时间都在等待。应该说CPU往framebuffer写的速度>LED从framebuffer读的速度还是很困难的。
如果CPU往framebuffer写的速度太慢,也会出现屏幕闪烁的问题。比如说要画一幅图,CPU首先将其填充为白色,这时LED刷新,屏幕显示为白色,之后开始画完其他内容,屏幕正常显示。这时给用户的感觉就是屏幕一闪。这就要求CPU尽快的画完一屏,尽量保证写一屏不要跨越LED刷新周期。
因此,在单framebuffer的时代,为了防止屏幕出现闪烁,我们一般是在内存中开辟一块与framebuffer同样大小的内容,将屏幕的内容都写好,然后再执行一次内存拷贝。从而使写framebuffer的时间尽可能的短。
但这种机制有问题,我以屏幕分辩率为320*240为例。
一块framebuffer的大小为:320*240*4=0.3072M。
也就是说,我要先在内存中填写0.3M的内存,然后再把这块内存拷贝到framebuffer中。为了简单起见,这里我举一个将屏幕置为白色的例子,排除屏幕内容计算的影响。
显示的实际过程为,将内存中0.3M置为0,然后读取这0.3M的内存,拷贝到Framebuffer中。
在我使用的嵌入式平台中,采用的是SDRAM,532Mhz的ARM11芯片。通过使用lmbench得到内存访问的速率为:
*Local* Communication bandwidths in MB/s - bigger is better
-----------------------------------------------------------
Host OS Pipe AF TCP File Mmap Bcopy Bcopy Mem Mem
UNIX reread reread (libc) (hand) read
write
--------- ------------- ---- ---- ---- ------ ------ -------- ---- -----
phone Linux 2.6 79.1 94.7 13.3 47.1 135.9 78.6 77.8 135. 205.9
很奇怪,为什么读会比写慢,可能与cache有关,这里先不用去管它。
下面我来计算单buffer所使用的时间。
将0.3M内存置为0:0.3072×1000/200=1.5ms。
读0.3M内存:0.3072×1000/135=2.7ms
将03M内存写到framebuffer:0:0.3072×1000/200=1.5ms。
总共时间为5.7ms。实际的传输情况要比这个多,因为还要涉及循环的开销。
5.7ms看起来还行。
当屏幕分辨率变大时,情况就不一样了。如果屏幕的分辨率扩大为800*600,那么其数据量将是320*240的6.25倍。那么单纯的显示一个白屏的时间,将为5.7*6.25=36.6ms,也就是说如果只是显示白屏的话,我们也最多显示30帧,这个时间实在是太长了。
并且如果我们只计算从内存拷贝到framebuffer的时间,其为
(2.7+1.5)*6.25=25.25ms。如何LED刷新频率为60hz,那么刷新一屏的时间将为18ms,这样即使单纯的从内存拷贝到framebuffer,写一屏的时间也大于LED的刷新频率,肯定会造成屏幕的闪烁。
单buffer的另外一个问题在于,其每次都要进行内存拷贝,这样其会重新刷新CPU中的数据cache,对软件的性能有不利的影响。

性能的改善:
从软件的角度来讲,每次尽量缩小刷新的区域,减少内存的传输。
从硬件角度来讲,采用更高的CPU,采用更快的DDR内存,提高内存的吞吐率。

下面再来说下双buffer。
双buffer的好处在于,在LED显示当前framebuffer时,软件可以直接向后台的framebuffer写,在写完之后只是两个buffer做下切换即可,不再需要内存拷贝,从而提高效率。
还是以显示一个320×240的白屏为例,其过程变成:
1、 直接向后面的framebuffer写,其花费时间为0.3072×1000/200=1.5ms。
2、 写完之后framebffer切换,这个时间可以忽略不计。
那么当屏幕变为800×600时,其所花费的时间为1.5*6.25=9.375,要比单buffer的效率提高2.6倍。
并且双buffer还有一个好处,由于其没有了内存拷贝的环节,其对数据cache的影响较小,对于提高软件性能有利。另外给framebuffer的数据置位,其必然要经过Cache,由于这些数据写完后不再使用,那么使用写透cache要比使用回写式cache效率高。

双buffer还有一个好处,就是可以利用GPU的硬加速。如果要利用GPU的硬加速,则显示的数据必须是在预留的物理内存中,这在单buffer机制中是不能实现的。

双buffer也有一个致命的弱点:那就是局部刷新。
在单buffer的情况下,很容易实现局部刷新,只需要把局部的数据拷贝到对应的位置就可以了。而双buffer来讲,如果要实现局部刷新,则必须先将当前显示的buffer数据拷贝到后面的buffer,然后再做局部刷新。这样对于双buffer的设备来讲,刷新整屏的效率要比局部刷新更高。

局部刷新的理想情况:
将局部要修改的数据,直接写到另外一个显存中,与前buffer做叠加。

应该说单buffer和双buffer各有擅长,关键在于如何灵活运用。

直写式(write
through),也叫写透,即CPU在向Cache写入数据的同时,也把数据写入主存以保证Cache和主存中相应单元数据的一致性,其特点是简单可靠,但由于CPU每次更新时都要对主存写入,速度必然受影响。
回写式(write
back),即CPU只向Cache写入,并用标记加以注明,直到Cache中被写过的块要被进入的信息块取代时,才一次性写入主存。这种方式考虑到写入的往往是中间结果,每次写入主存速度慢而且不必要。其特点是速度快,避免了不必要的冗余写操作,但结构上较复杂。
直写式和回写式有着截然不同的操作,在不同的场合,不同的内存块使用不同的回写策略(如果你的系统可以实现的话)要比使用一种策略要高效得多。具体一点,对于反复存取的内存块置成写回,而把一次写入而很长时间以后再使用的内存置为写透,可以大大提高Cache的效率。
第一点很容易理解,第二点就需要琢磨一下了,由于写透的操作是,当缓存有该地址的数据时同时更新缓存和主存,当缓存没有该地址数据直接写主存,忽略缓存。当该地址的数据很长时间后才被使用到,那么在使用的时候该数据肯定不在Cache中(被替换了),所以不如直接写入主存来得直接;
相反,如果使用写回操作,当
Cache中有该地址数据,需要更新该数据,设置dirty位,很长时间后再使用该数据或被替换的时候才将其刷进主存,这样白白的占据了宝贵的Cache;而当
Cache没有该地址数据时,情况更糟糕,首先需要将相应的主存数据(一个Cache
line)导入Cache,再更新数据,设置dirty位,再等待被刷回内存,这种情况不仅占用了Cache的空间,还多一次从主存中导入数据的过程,同样占据总线,开销很大。至于为什么要先从主存中导入数据,是因为Cache往主存回写数据时是按照一个Cache
line 单位来写的,但被更新的数据可能没有一个Cache
line这么多,所以为了保证数据一致性,必须先把数据导入Cache,更新后再刷回来。
对于很多视频解码来说,帧写入过程是一个一次性的动作,只有在下一次作为参考帧时才会被使用到,所以帧缓冲内存可以设置为写透操作,而下一次使用它的时候很可能是作为参考帧来使用,而作为参考帧不需要反复的存取,只需一次读操作就可以了,所以效率并不会因为不经过Cache而降低。实验证明该方法可以使
mpeg4 sp解码提高20-30%的效率。

vim自带的自动补全功能

vi7.0版本自带了自动补全功能omni-completion。
那么Vim是如何找到匹配的单词的呢?在默认的情况下,Vim在查找一个单词时是按照如下的步骤:
1 在当前文件中进行查找
2 在其他窗口中进行查找
3 在其他的已装入的缓冲区中进行查找
4 在没有装入缓冲区的文件中进行查找
5 在当前的标记(tag)列表是进行查找
6 在所有的由当前文件的#include包含进来的文件中进行查找
当然了我们也可以自定义我们的查找顺序.
我们在使用自动完成功能时的命令CTRL-P是向后查找匹配的单词,而还有一个命令CTRL-N是向前查找匹配的单词.他们有同样的功能和作用,所不同的只是查找方向上的不同.
Vim还提供了许多的命令可以使得我们来自定义我们的一些查找上的特征.例如我们可以用下面的命令来告诉Vim在在自动完成的查找过程中忽略大小写的区别:
:set ignorecase
这样以后如果我们输入ins,Vim就会认为是INSERT,Inside或者是instep.当然了前提是在我们所编辑的文本中含有这些词,要不就会找得到了.
为了能够精确的进行查找来自动完成,我们并不希望上面的情况出现,我们可以设置一些选项来告诉Vim区分大小写的情况.这时我们要用到下面的命令:
:set infercase
这样以后如果我们再输入ins,与其相匹配的列表就成为了instep,inside,insert.我们可以通过按CTRL-P或是CTRL-N来进行匹配完成.
在大多数情况下,Vim默认的设置可以很好的来完成工作,但是有时我们要定义自己的一些完成的选项,这时我们就要用到complete这个选项了.这个选项的格式如下:
:set complete=key,key,key
而这个命令中可能出现的key值如下:
. 当前文件
b 已被装缓冲区,但是没有在窗口内的文件
d 在当前的文件中定义和由#include包含进来的文件
i 由#include包含进来的文件
k 由dictionary选项定义的文件
kfile 名为{file}的文件
t 标记(tags)文件
u 没有载入的缓冲区
w 在其他窗口中的文件
我们可以使用path选项来告诉Vim如何来查找我们在当前文件中所包含进来的文件.我们还可以指定一个字典,这个选项的格式如下:
:set dictionary=file,file,....
这个选项定义了由命令CTRL-P和CTRL-N进行匹配查找时所要查找的文件.在Linux系统中这个定义文件在/usr/dict/words中,所以如果我们要将这个文件添加进来进行查找的话,我们就要用到下面的命令:
:set dictionary=/usr/dict/words
如果我们要使用一个我们自己的文件也可以这样的来设置
:set dictionary=/home/oualline/words,/usr/doc/words
我们也可以指定一个字典文件和k选项组合使用:
:set dictionary=k/usr/oualline/words
我们也可以多次的使用k这个标记选项:
:set dictionary=k/usr/dict/words,k/usr/share/words
在上面提到的CTRL-P和CTRL-N进行查找匹配时查找的范围比较的宽范,我们当然也可以使用命令进行一些比较严格的查找.这时我们可以使用命令CTRL-X.当我们输入CTRL-X时我们会进入CTRL-X的一个子模式.这时我们可以使用下面的命令进行查找:
CTRL-D 宏定义
CTRL-F 文件名
CTRL-K 字典
CTRL-I 当前文件以及由#include包含进来的文件
CTRL-L 整个行
CTRL-] 标记(tags)
CTRL-P 向前查找,与没有CTRL-X命令时相同
CTRL-N 向后查找,与没有CTRL-X命令时相同
CTRL-X
CTRL-D命令查找宏定义.他也会查找#include文件.当我们执行完这个命令以后就可以使用CTRL-P,CTRL-N来进行匹配查找.
例如我们可以编辑下面的测试文件:
include.h文件中的内容
#define MAX(x,y) ((x)<(y)?(y):(x))
#define MIN(x,y) ((x)<(y)?(x):(y))
int sum(int i1,int i2)
{return (i1+i2);}
main.c文件中的内容:
#include "include.h"
#define MORE "/usr/ucb/more"
这时我们开始编辑main.c文件,如果我们按下CTRL-X我们就会进入CTRL-X的子模式.如果我们要查找一个宏定义,我们可以按下CTRL-D,这时就会在屏幕的底部简单的显示出有多少匹配的选项.这样我们就可以用CTRL-P和CTRL-N来进行自动完成的功能了.而命令CTRL-X
CTRL-]则是查找下一个标记(tag),标记是一个C函数的定义.我们可以用命令ctags命令来生成一个C函数定义的列表.我们可以这样的来使用这个命令:
$ctags *.c *.h
这样以后我们就可以在插入模式入下用CTRL-X
CTRL-]命令来进行标记的查找和匹配了.
在默认的情况下,vim编辑器只是简单的显示出标记的名字,我们可以执行下面的命令,这样以后就可以显示出整个标记了:
:set showfulltag
我们可以使用CTRL-X
CTRL-F命令来匹配文件名.他会在当前的目录下查找文件并会显示出匹配的内容,这时你就可以用CTRL-P和CTRL-N命令来选择你想要的匹配选项了.
到目前为止我们所说还只是对单词进行操作,我们可以用命令CTRL-X
CTRL-L对一行进行匹配操作,同样的我们也可以用CTRL-N和CTRL-P来进行选项的匹配.我们还可以在输入CTRL-X命令后用CTRL-Y向下滚动文本,而用CTRL-E向上滚动文本.

上一篇 / 下一篇 2005-07-26 11:16:31 / 个人分类:Linux
查看( 31 ) / 评论( 0 ) / 评分( 0 / 0 )
我们在用Vim来处理文件时可以使用Vim的自动完成功能来大大加速我们的工作速度.所谓的自动完成也就是说当我们输入一个单词的一部分以后,按CTRL
-P,Vim就会自动的来完成剩下的部分.我们在前面的学习过程中曾用:abbreviate命令来简记某一个单词来达到自动完成的目的,而在这里我们将
看到是一个更加强大的自动完成功能.Vim能非常简单和灵活的来决定要用哪一个单词来自动完成.
我们在使用Vim这个强大的自动完成功能的同时,还可以自已定义我们的自动完成的特征,而且还可以使用不同类型的自动完成功能.[@more@]我们在用Vim来处理文件时可以使用Vim的自动完成功能来大大加速我们的工作速度.所谓的自动完成也就是说当我们输入一个单词的一部分以后,按CTRL-P,Vim就会自动的来完成剩下的部分.我们在前面的学习过程中曾用:abbreviate命令来简记某一个单词来达到自动完成的目的,而在这里我们将看到是一个更加强大的自动完成功能.Vim能非常简单和灵活的来决定要用哪一个单词来自动完成.
我们在使用Vim这个强大的自动完成功能的同时,还可以自已定义我们的自动完成的特征,而且还可以使用不同类型的自动完成功能.
如果我们在编写C程序,而我们所谓得到的下面的一个句子:
total=ch_array[0]+ch_array[1]+ch_array[2]
这时我们输入total=ch_array[0]+ch_,然后按下CTRL-P,Vim就会自动的替我们完成其余的部分,这时我们得到将是
total=ch_array[0]+ch_array
由此可以看到我们在处理文件时用这样的方式可以大大的加快我们的处理速度.
那么Vim是如何找到匹配的单词的呢?在默认的情况下,Vim在查找一个单词时是按照如下的步骤:
1 在当前文件中进行查找
2 在其他窗口中进行查找
3 在其他的已装入的缓冲区中进行查找
4 在没有装入缓冲区的文件中进行查找
5 在当前的标记(tag)列表是进行查找
6 在所有的由当前文件的#include包含进来的文件中进行查找
当然了我们也可以自定义我们的查找顺序.
我们在使用自动完成功能时的命令CTRL-P是向后查找匹配的单词,而还有一个命令CTRL-N是向前查找匹配的单词.他们有同样的功能和作用,所不同的只是查找方向上的不同.
Vim还提供了许多的命令可以使得我们来自定义我们的一些查找上的特征.例如我们可以用下面的命令来告诉Vim在在自动完成的查找过程中忽略大小写的区别:
:set ignorecase
这样以后如果我们输入ins,Vim就会认为是INSERT,Inside或者是instep.当然了前提是在我们所编辑的文本中含有这些词,要不就会找得到了.
为了能够精确的进行查找来自动完成,我们并不希望上面的情况出现,我们可以设置一些选项来告诉Vim区分大小写的情况.这时我们要用到下面的命令:
:set infercase
这样以后如果我们再输入ins,与其相匹配的列表就成为了instep,inside,insert.我们可以通过按CTRL-P或是CTRL-N来进行匹配完成.
在大多数情况下,Vim默认的设置可以很好的来完成工作,但是有时我们要定义自己的一些完成的选项,这时我们就要用到complete这个选项了.这个选项的格式如下:
:set complete=key,key,key
而这个命令中可能出现的key值如下:
. 当前文件
b 已被装缓冲区,但是没有在窗口内的文件
d 在当前的文件中定义和由#include包含进来的文件
i 由#include包含进来的文件
k 由dictionary选项定义的文件
kfile 名为{file}的文件
t 标记(tags)文件
u 没有载入的缓冲区
w 在其他窗口中的文件
我们可以使用path选项来告诉Vim如何来查找我们在当前文件中所包含进来的文件.我们还可以指定一个字典,这个选项的格式如下:
:set dictionary=file,file,....
这个选项定义了由命令CTRL-P和CTRL-N进行匹配查找时所要查找的文件.在Linux系统中这个定义文件在/usr/dict/words中,所以如果我们要将这个文件添加进来进行查找的话,我们就要用到下面的命令:
:set dictionary=/usr/dict/words
如果我们要使用一个我们自己的文件也可以这样的来设置
:set dictionary=/home/oualline/words,/usr/doc/words
我们也可以指定一个字典文件和k选项组合使用:
:set dictionary=k/usr/oualline/words
我们也可以多次的使用k这个标记选项:
:set dictionary=k/usr/dict/words,k/usr/share/words
在上面提到的CTRL-P和CTRL-N进行查找匹配时查找的范围比较的宽范,我们当然也可以使用命令进行一些比较严格的查找.这时我们可以使用命令CTRL-X.当我们输入CTRL-X时我们会进入CTRL-X的一个子模式.这时我们可以使用下面的命令进行查找:
CTRL-D 宏定义
CTRL-F 文件名
CTRL-K 字典
CTRL-I 当前文件以及由#include包含进来的文件
CTRL-L 整个行
CTRL-] 标记(tags)
CTRL-P 向前查找,与没有CTRL-X命令时相同
CTRL-N 向后查找,与没有CTRL-X命令时相同
CTRL-X
CTRL-D命令查找宏定义.他也会查找#include文件.当我们执行完这个命令以后就可以使用CTRL-P,CTRL-N来进行匹配查找.
例如我们可以编辑下面的测试文件:
include.h文件中的内容
#define MAX(x,y) ((x)<(y)?(y):(x))
#define MIN(x,y) ((x)<(y)?(x):(y))
int sum(int i1,int i2)
{return (i1+i2);}
main.c文件中的内容:
#include "include.h"
#define MORE "/usr/ucb/more"
这时我们开始编辑main.c文件,如果我们按下CTRL-X我们就会进入CTRL-X的子模式.如果我们要查找一个宏定义,我们可以按下CTRL-D,这时就会在屏幕的底部简单的显示出有多少匹配的选项.这样我们就可以用CTRL-P和CTRL-N来进行自动完成的功能了.而命令CTRL-X
CTRL-]则是查找下一个标记(tag),标记是一个C函数的定义.我们可以用命令ctags命令来生成一个C函数定义的列表.我们可以这样的来使用这个命令:
$ctags *.c *.h
这样以后我们就可以在插入模式入下用CTRL-X
CTRL-]命令来进行标记的查找和匹配了.
在默认的情况下,vim编辑器只是简单的显示出标记的名字,我们可以执行下面的命令,这样以后就可以显示出整个标记了:
:set showfulltag
我们可以使用CTRL-X
CTRL-F命令来匹配文件名.他会在当前的目录下查找文件并会显示出匹配的内容,这时你就可以用CTRL-P和CTRL-N命令来选择你想要的匹配选项了.
到目前为止我们所说还只是对单词进行操作,我们可以用命令CTRL-X
CTRL-L对一行进行匹配操作,同样的我们也可以用CTRL-N和CTRL-P来进行选项的匹配.我们还可以在输入CTRL-X命令后用CTRL-Y向下滚动文本,而用CTRL-E向上滚动文本.

Bash 使用技巧

Bash 是我们经常与之打交道的 Shell
程序,本文针对其使用技巧进行了搜罗。相信在你看过这些内容之后,定会在 Bash
的世界里游刃有余。
从历史中执行命令
有时候,我们需要在 Bash
中重复执行先前的命令。你当然可以使用上方向键来查看之前曾经运行过的命令。但这里有一种更好的方式:你可以按
Ctrl + r 组合键进入历史搜索模式,一旦找到需要重复执行的命令,按回车键即可。
重复命令参数
先来看一个例子:
mkdir /path/to/exampledir
cd !$
本例中,第一行命令将创建一个目录,而第二行的命令则转到刚创建的目录。这里,"!$"的作用就是重复前一个命令的参数。事实上,不仅是命令的参数可以重复,命令的选项同样可以。另外,Esc
+ . 快捷键可以切换这些命令参数或选项。
用于编辑的快捷键
Ctrl + a:将光标定位到命令的开头
Ctrl + e:与上一个快捷键相反,将光标定位到命令的结尾
Ctrl + u:剪切光标之前的内容
Ctrl + k:与上一个快捷键相反,剪切光标之后的内容
Ctrl + y:粘贴以上两个快捷键所剪切的内容
Ctrl + t:交换光标之前两个字符的顺序
Ctrl + w:删除光标左边的参数(选项)或内容
Ctrl + l:清屏
处理作业
首先,使用 Ctrl + z
快捷键可以让正在执行的命令挂起。如果要让该进程在后台执行,那么可以执行 bg
命令。而 fg 命令则可以让该进程重新回到前台来。使用 jobs
命令能够查看到哪些进程在后台执行。
你也可以在 fg 或 bg 命令中使用作业 id,如:
fg %3
又如:
bg %7
使用置换
命令置换
先看例子:
du -h -a -c $(find . -name *.conf 2>&-)
注意 $() 中的部分,这将告诉 Bash 运行 find 命令,然后把返回的结果作为 du
的参数。
进程置换
仍然先看例子:
diff <(ps axo comm) <(ssh user@host ps axo comm)
该命令将比较本地系统和远程系统中正在运行的进程。请注意 <() 中的部分。
xargs
看例:
find . -name *.conf -print0 | xargs -0 grep -l -Z mem_limit | xargs -0 -i
cp {} {}.bak
该命令将备份当前目录中的所有 .conf 文件。
使用管道
下面是一个简单的使用管道的例子:
ps aux | grep init
这里,"|"操作符将 ps aux 的输出重定向给 grep init。
下面还有两个稍微复杂点的例子:
ps aux | tee filename | grep init
及:
ps aux | tee -a filename | grep init
将标准输出保存为文件
你可以将命令的标准输出内容保存到一个文件中,举例如下:
ps aux > filename
注意其中的">"符号。
你也可以将这些输出内容追加到一个已存在的文件中:
ps aux >> filename
你还可以分割一个较长的行:
command1 | command2 | ... | commandN > tempfile1
cat tempfile1 | command1 | command2 | ... | commandN > tempfile2
标准流:重定向与组合
重定向流的例子:
ps aux 2>&1 | grep init
这里的数字代表:
0:stdin
1:stdout
2:sterr
上面的命令中,"grep init"不仅搜索"ps aux"的标准输出,而且搜索 sterr 输出。

你从未用过的 10 条 Linux 命令?

1. pgrep:比如,你可以使用 pgrep -u root 来代替 ps -ef | egrep '^root ' |
awk '{print $2}',以便抓取属于 root 的 PID。
2.
pstree:我觉得这个命令很酷,它可以直接列出进程树,或者换句话说是按照树状结构来列出进程。
3.
bc:这个命令在我的系统中没有找到,可能需要安装。这是用来执行计算的一个命令,如使用它来开平方根。
4.
split:这是一个很有用的命令,它可以将一个大文件分割成几个小的部分。比如:split
-b 2m largefile LF_ 会将 largefile 分割成带有 LF 文件名前缀且大小为 2 MB
的小文件。
5.
nl:能够显示行号的命令。在阅读脚本或代码时,这个命令应该非常有用。如:nl
wireless.h | head。
6.
mkfifo:作者说这是他最喜欢的命令。该命令使得其他命令能够通过一个命名的管道进行通信。嗯,听起来有点空洞。举例说明,先创建一个管道并写入内容:
mkfifo ive-been-piped
ls -al split/* | head > ive-been-piped
然后就可以读取了:head ive-been-piped。
7. ldd:其作用是输出指定文件依赖的动态链接库。比如,通过 ldd
/usr/java/jre1.5.0_11/bin/java 可以了解java 依赖(动态链接)了哪些库。
8. col:可以将 man 手册页保存为无格式的文本文件。如:
PAGER=cat
man less | col -b > less.txt
9. xmlwf:能够检测 XML 文档是否良好。比如:
curl -s 'http://bashcurescancer.com' > bcc.html
xmlwf bcc.html
perl -i -pe 's@<br/>@<br>@g' bcc.html
xmlwf bcc.html
bcc.html:104:2: mismatched tag
10. lsof:列出打开的文件。如:通过 lsof | grep TCP 可以找到打开的端口。

UNIX 高手的 10 个习惯

当您经常使用某个系统时,往往会陷入某种固定的使用模式。有时,您没有养成以尽可能最好的方式做事的习惯。有时,您的不良习惯甚至会导致出现混乱。
纠正此类缺点的最佳方法之一,就是有意识地采用抵制这些坏习惯的好习惯。本文提出了
10 个值得采用的 UNIX
命令行习惯——帮助您克服许多常见使用怪癖,并在该过程中提高命令行工作效率的好习惯。下面列出了这
10 个好习惯,之后对进行了更详细的描述。
采用 10 个好习惯
要采用的十个好习惯为:
在单个命令中创建目录树。
更改路径;不要移动存档。
将命令与控制操作符组合使用。
谨慎引用变量。
使用转义序列来管理较长的输入。
在列表中对命令分组。
在 find 之外使用 xargs。
了解何时 grep 应该执行计数——何时应该绕过。
匹配输出中的某些字段,而不只是对行进行匹配。
停止对 cat 使用管道。
在单个命令中创建目录树
清单 1 演示了最常见的 UNIX 坏习惯之一:一次定义一个目录树。
清单 1. 坏习惯 1 的示例:单独定义每个目录树
~ $ mkdir tmp
~ $ cd tmp
~/tmp $ mkdir a
~/tmp $ cd a
~/tmp/a $ mkdir b
~/tmp/a $ cd b
~/tmp/a/b/ $ mkdir c
~/tmp/a/b/ $ cd c
~/tmp/a/b/c $

使用 mkdir 的 -p
选项并在单个命令中创建所有父目录及其子目录要容易得多。但是即使对于知道此选项的管理员,他们在命令行上创建子目录时也仍然束缚于逐步创建每级子目录。花时间有意识地养成这个好习惯是值得的:
清单 2. 好习惯 1 的示例:使用一个命令来定义目录树~ $ mkdir -p tmp/a/b/c

您可以使用此选项来创建整个复杂的目录树(在脚本中使用是非常理想的),而不只是创建简单的层次结构。例如:
清单 3. 好习惯 1 的另一个示例:使用一个命令来定义复杂的目录树~ $ mkdir -p
project/{lib/ext,bin,src,doc/{html,info,pdf},demo/stat/a}

过去,单独定义目录的唯一借口是您的 mkdir
实现不支持此选项,但是在大多数系统上不再是这样了。IBM、AIX®、mkdir、GNU
mkdir 和其他遵守单一 UNIX 规范 (Single UNIX Specification)
的系统现在都具有此选项。
对于仍然缺乏该功能的少数系统,您可以使用 mkdirhier
脚本(请参见参考资料),此脚本是执行相同功能的 mkdir 的包装:~ $ mkdirhier
project/{lib/ext,bin,src,doc/{html,info,pdf},demo/stat/a}

更改路径;不要移动存档
另一个不良的使用模式是将 .tar
存档文件移动到某个目录,因为该目录恰好是您希望在其中提取 .tar
文件的目录。其实您根本不需要这样做。您可以随心所欲地将任何 .tar
存档文件解压缩到任何目录——这就是 -C
选项的用途。在解压缩某个存档文件时,使用 -C
选项来指定要在其中解压缩该文件的目录:
清单 4. 好习惯 2 的示例:使用选项 -C 来解压缩 .tar 存档文件~ $ tar xvf -C
tmp/a/b/c newarc.tar.gz

相对于将存档文件移动到您希望在其中解压缩它的位置,切换到该目录,然后才解压缩它,养成使用
-C 的习惯则更加可取——当存档文件位于其他某个位置时尤其如此。

将命令与控制操作符组合使用
您可能已经知道,在大多数 Shell
中,您可以在单个命令行上通过在命令之间放置一个分号 (;)
来组合命令。该分号是 Shell 控制操作符,
虽然它对于在单个命令行上将离散的命令串联起来很有用,但它并不适用于所有情况。例如,假设您使用分号来组合两个命令,其中第二个命令的正确执行完全依赖
于第一个命令的成功完成。如果第一个命令未按您预期的那样退出,第二个命令仍然会运行——结果会导致失败。相反,应该使用更适当的控制操作符(本文将描述
其中的部分操作符)。只要您的 Shell 支持它们,就值得养成使用它们的习惯。
仅当另一个命令返回零退出状态时才运行某个命令
使用 && 控制操作符来组合两个命令,以便仅当
第一个命令返回零退出状态时才运行第二个命令。换句话说,如果第一个命令运行成功,则第二个命令将运行。如果第一个命令失败,则第二个命令根本就不运行。例如:
清单 5. 好习惯 3 的示例:将命令与控制操作符组合使用~ $ cd tmp/a/b/c && tar
xvf ~/archive.tar

在此例中,存档的内容将提取到 ~/tmp/a/b/c
目录中,除非该目录不存在。如果该目录不存在,则 tar
命令不会运行,因此不会提取任何内容。
仅当另一个命令返回非零退出状态时才运行某个命令
类似地,||
控制操作符分隔两个命令,并且仅当第一个命令返回非零退出状态时才运行第二个命令。换句话说,如果第一个命令成功,则第二个命令不会运行。如果第一个命令失败,则第二个命令才会
运行。在测试某个给定目录是否存在时,通常使用此操作符,如果该目录不存在,则创建它:
清单 6. 好习惯 3 的另一个示例:将命令与控制操作符组合使用~ $ cd tmp/a/b/c
|| mkdir -p tmp/a/b/c

您还可以组合使用本部分中描述的控制操作符。每个操作符都影响最后的命令运行:
清单 7. 好习惯 3 的组合示例:将命令与控制操作符组合使用~ $ cd tmp/a/b/c ||
mkdir -p tmp/a/b/c && tar xvf -C tmp/a/b/c ~/archive.tar

谨慎引用变量
始终要谨慎使用 Shell
扩展和变量名称。一般最好将变量调用包括在双引号中,除非您有不这样做的足够理由。类似地,如果您直接在字母数字文本后面使用变量名称,则还要确保将该变
量名称包括在方括号 ([]) 中,以使其与周围的文本区分开来。否则,Shell
将把尾随文本解释为变量名称的一部分——并且很可能返回一个空值。清单 8
提供了变量的各种引用和非引用及其影响的示例。
清单 8. 好习惯 4 的示例:引用(和非引用)变量~ $ ls tmp/
a b
~ $ VAR="tmp/*"
~ $ echo $VAR
tmp/a tmp/b
~ $ echo "$VAR"
tmp/*
~ $ echo $VARa
~ $ echo "$VARa"
~ $ echo "${VAR}a"
tmp/*a
~ $ echo ${VAR}a
tmp/a
~ $

使用转义序列来管理较长的输入
您或许看到过使用反斜杠 (\)
来将较长的行延续到下一行的代码示例,并且您知道大多数 Shell
都将您通过反斜杠联接的后续行上键入的内容视为单个长行。然而,您可能没有在命令行中像通常那样利用此功能。如果您的终端无法正确处理多行回绕,或者您的
命令行比通常小(例如在提示符下有长路经的时候),反斜杠就特别有用。反斜杠对于了解键入的长输入行的含义也非常有用,如以下示例所示:
清单 9. 好习惯 5 的示例:将反斜杠用于长输入~ $ cd tmp/a/b/c || \
> mkdir -p tmp/a/b/c && \
> tar xvf -C tmp/a/b/c ~/archive.tar

或者,也可以使用以下配置:
清单 10. 好习惯 5 的替代示例:将反斜杠用于长输入~ $ cd tmp/a/b/c \
> || \
> mkdir -p tmp/a/b/c \
> && \
> tar xvf -C tmp/a/b/c ~/archive.tar

然而,当您将输入行划分到多行上时,Shell
始终将其视为单个连续的行,因为它总是删除所有反斜杠和额外的空格。
注意:在大多数 Shell
中,当您按向上箭头键时,整个多行输入将重绘到单个长输入行上。

在列表中对命令分组
大多数 Shell
都具有在列表中对命令分组的方法,以便您能将它们的合计输出向下传递到某个管道,或者将其任何部分或全部流重定向到相同的地方。您一般可以通过在某个
Subshell 中运行一个命令列表或通过在当前 Shell
中运行一个命令列表来实现此目的。
在 Subshell 中运行命令列表
使用括号将命令列表包括在单个组中。这样做将在一个新的 Subshell
中运行命令,并允许您重定向或收集整组命令的输出,如以下示例所示:
清单 11. 好习惯 6 的示例:在 Subshell 中运行命令列表~ $ ( cd tmp/a/b/c/ ||
mkdir -p tmp/a/b/c && \
> VAR=$PWD; cd ~; tar xvf -C $VAR archive.tar ) \
> | mailx admin -S "Archive contents"

在此示例中,该存档的内容将提取到 tmp/a/b/c/
目录中,同时将分组命令的输出(包括所提取文件的列表)通过邮件发送到地址
admin。
当您在命令列表中重新定义环境变量,并且您不希望将那些定义应用于当前 Shell
时,使用 Subshell 更可取。
在当前 Shell 中运行命令列表
将命令列表用大括号 ({}) 括起来,以在当前 Shell
中运行。确保在括号与实际命令之间包括空格,否则 Shell
可能无法正确解释括号。此外,还要确保列表中的最后一个命令以分号结尾,如以下示例所示:
清单 12. 好习惯 6 的另一个示例:在当前 Shell 中运行命令列表~ $ { cp
${VAR}a . && chown -R guest.guest a && \
> tar cvf newarchive.tar a; } | mailx admin -S "New archive"

在 find 之外使用 xargs
使用 xargs 工具作为筛选器,以充分利用从 find 命令挑选的输出。find
运行通常提供与某些条件匹配的文件列表。此列表被传递到 xargs
上,后者然后使用该文件列表作为参数来运行其他某些有用的命令,如以下示例所示:
清单 13. xargs 工具的经典用法示例~ $ find some-file-criteria
some-file-path | \
> xargs some-great-command-that-needs-filename-arguments

然而,不要将 xargs 仅看作是 find
的辅助工具;它是一个未得到充分利用的工具之一,当您养成使用它的习惯时,将会希望进行所有试验,包括以下用法。
传递空格分隔的列表
在最简单的调用形式中,xargs
就像一个筛选器,它接受一个列表(每个成员分别在单独的行上)作为输入。该工具将那些成员放置在单个空格分隔的行上:
清单 14. xargs 工具产生的输出示例~ $ xargs
a
b
c
Control-D
a b c
~ $

您可以发送通过 xargs
来输出文件名的任何工具的输出,以便为其他某些接受文件名作为参数的工具获得参数列表,如以下示例所示:
清单 15. xargs 工具的使用示例~/tmp $ ls -1 | xargs
December_Report.pdf README a archive.tar mkdirhier.sh
~/tmp $ ls -1 | xargs file
December_Report.pdf: PDF document, version 1.3
README: ASCII text
a: directory
archive.tar: POSIX tar archive
mkdirhier.sh: Bourne shell script text executable
~/tmp $

xargs
命令不只用于传递文件名。您还可以在需要将文本筛选到单个行中的任何时候使用它:
清单 16. 好习惯 7 的示例:使用 xargs 工具来将文本筛选到单个行中~/tmp $ ls
-l | xargs
-rw-r--r-- 7 joe joe 12043 Jan 27 20:36 December_Report.pdf -rw-r--r-- 1 \
root root 238 Dec 03 08:19 README drwxr-xr-x 38 joe joe 354082 Nov 02 \
16:07 a -rw-r--r-- 3 joe joe 5096 Dec 14 14:26 archive.tar -rwxr-xr-x 1 \
joe joe 3239 Sep 30 12:40 mkdirhier.sh
~/tmp $

谨慎使用 xargs
从技术上讲,使用 xargs 很少遇到麻烦。缺省情况下,文件结束字符串是下划线
(_);如果将该字符作为单个输入参数来发送,则它之后的所有内容将被忽略。为了防止这种情况发生,可以使用
-e 标志,它在不带参数的情况下完全禁用结束字符串。

了解何时 grep 应该执行计数——何时应该绕过
避免通过管道将 grep 发送到 wc -l 来对输出行数计数。grep 的 -c
选项提供了对与特定模式匹配的行的计数,并且一般要比通过管道发送到 wc
更快,如以下示例所示:
清单 17. 好习惯 8 的示例:使用和不使用 grep 的行计数~ $ time grep and
tmp/a/longfile.txt | wc -l
2811
real 0m0.097s
user 0m0.006s
sys 0m0.032s
~ $ time grep -c and tmp/a/longfile.txt
2811
real 0m0.013s
user 0m0.006s
sys 0m0.005s
~ $

除了速度因素外,-c 选项还是执行计数的好方法。对于多个文件,带 -c 选项的
grep 返回每个文件的单独计数,每行一个计数,而针对 wc
的管道则提供所有文件的组合总计数。
然而,不管是否考虑速度,此示例都表明了另一个要避免地常见错误。这些计数方法仅提供包含匹配模式的行数——如果那就是您要查找的结果,这没什么问题。但是在行中具有某个特定模式的多个实例的情况下,这些方法无法为您提供实际匹配实例数量
的真实计数。归根结底,若要对实例计数,您还是要使用 wc 来计数。首先,使用
-o 选项(如果您的版本支持它的话)来运行 grep 命令。此选项仅
输出匹配的模式,每行一个模式,而不输出行本身。但是您不能将它与 -c
选项结合使用,因此要使用 wc -l 来对行计数,如以下示例所示:
清单 18. 好习惯 8 的示例:使用 grep 对模式实例计数~ $ grep -o and
tmp/a/longfile.txt | wc -l
3402
~ $

在此例中,调用 wc 要比第二次调用 grep 并插入一个虚拟模式(例如 grep
-c)来对行进行匹配和计数稍快一点。

匹配输出中的某些字段,而不只是对行进行匹配
当您只希望匹配输出行中特定字段 中的模式时,诸如 awk 等工具要优于 grep。
下面经过简化的示例演示了如何仅列出 12 月修改过的文件。
清单 19. 坏习惯 9 的示例:使用 grep 来查找特定字段中的模式~/tmp $ ls -l
/tmp/a/b/c | grep Dec
-rw-r--r-- 7 joe joe 12043 Jan 27 20:36 December_Report.pdf
-rw-r--r-- 1 root root 238 Dec 03 08:19 README
-rw-r--r-- 3 joe joe 5096 Dec 14 14:26 archive.tar
~/tmp $

在此示例中,grep 对行进行筛选,并输出其修改日期和名称中带 Dec
的所有文件。因此,诸如 December_Report.pdf
等文件是匹配的,即使它自从一月份以来还未修改过。这可能不是您希望的结果。为了匹配特定字段中的模式,最好使用
awk,其中的一个关系运算符对确切的字段进行匹配,如以下示例所示:
清单 20. 好习惯 9 的示例:使用 awk 来查找特定字段中的模式~/tmp $ ls -l |
awk '$6 == "Dec"'
-rw-r--r-- 3 joe joe 5096 Dec 14 14:26 archive.tar
-rw-r--r-- 1 root root 238 Dec 03 08:19 README
~/tmp $

有关如何使用 awk 的更多详细信息,请参见参考资料。

停止对 cat 使用管道
grep 的一个常见的基本用法错误是通过管道将 cat 的输出发送到 grep
以搜索单个文件的内容。这绝对是不必要的,纯粹是浪费时间,因为诸如 grep
这样的工具接受文件名作为参数。您根本不需要在这种情况下使用
cat,如以下示例所示:
清单 21. 好习惯和坏习惯 10 的示例:使用带和不带 cat 的 grep
~ $ time cat tmp/a/longfile.txt | grep and
2811
real 0m0.015s
user 0m0.003s
sys 0m0.013s
~ $ time grep and tmp/a/longfile.txt
2811
real 0m0.010s
user 0m0.006s
sys 0m0.004s
~ $

此错误存在于许多工具中。由于大多数工具都接受使用连字符 (-)
的标准输入作为一个参数,因此即使使用 cat 来分散 stdin
中的多个文件,参数也通常是无效的。仅当您使用带多个筛选选项之一的 cat
时,才真正有必要在管道前首先执行连接。

结束语:养成好习惯
最好检查一下您的命令行习惯中的任何不良的使用模式。不良的使用模式会降低您的速度,并且通常会导致意外错误。本文介绍了
10
个新习惯,它们可以帮助您摆脱许多最常见的使用错误。养成这些好习惯是加强您的
UNIX 命令行技能的积极步骤。

Linux 系统下查找进程并终止命令详解

使用linux操作系统,难免遇到一些软件"卡壳"的问题,这时就需要使用linux下强大的kill命令来结束相关进程。这在linux系统下是极其容易的事情,你只需要kill
xxx即可,这里xxx代表与此软件运行相关的进程PID号。

首先,我们需要使用linux下另外一个命令ps查找与进程相关的PID号:ps aux |
grep program_filter_word

1)ps a 显示现行终端机下的所有程序,包括其他用户的程序。

2)ps -A 显示所有程序。

3)ps c
列出程序时,显示每个程序真正的指令名称,而不包含路径,参数或常驻服务的标示。

4)ps -e 此参数的效果和指定"A"参数相同。

5)ps e 列出程序时,显示每个程序所使用的环境变量。

6)ps f 用ASCII字符显示树状结构,表达程序间的相互关系。

7)ps -H 显示树状结构,表示程序间的相互关系。

8)ps -N 显示所有的程序,除了执行ps指令终端机下的程序之外。

9)ps s 采用程序信号的格式显示程序状况。

10)ps S 列出程序时,包括已中断的子程序资料。

11)ps -t<终端机编号> 指定终端机编号,并列出属于该终端机的程序的状况。

12)ps u 以用户为主的格式来显示程序状况。

13)ps x 显示所有程序,不以终端机来区分。

最常用的方法是ps
aux,然后再通过管道使用grep命令过滤查找特定的进程,然后再对特定的进程进行操作。

其次,使用kill命令结束进程:kill xxx

1)作用
kill命令用来中止一个进程。

2)格式
kill [ -s signal | -p ] [ -a ] pid ...
kill -l [ signal ]

3)参数
-s:指定发送的信号。
-p:模拟发送信号。
-l:指定信号的名称列表。
pid:要中止进程的ID号。
Signal:表示信号。

4)说明
进程是Linux系统中一个非常重要的概念。Linux是一个多任务的操作系统,系统上经常同时运行着多个进程。我们不关心这些进程究竟是如何分配的,或者是内核如何管理分配时间片的,所关心的是如何去控制这些进程,让它们能够很好地为用户服务。

Linux操作系统包括三种不同类型的进程,每种进程都有自己的特点和属性。交互进程是由一个Shell启动的进程。交互进程既可以在前台运行,也可以在后台运行。批处理进程和终端没有联系,是一个进程序列。监控进程(也称系统守护进程)是Linux系统启动时启动的进程,并在后台运行。例如,httpd
是著名的Apache服务器的监控进程。

kill命令的工作原理是,向Linux系统的内核发送一个系统操作信号和某个程序的进程标识号,然后系统内核就可以对进程标识号指定的进程进行操作。比如在top命令中,我们看到系统运行许多进程,有时就需要使用kill中止某些进程来提高系统资源。在讲解安装和登陆命令时,曾提到系统多个虚拟控制台的作用是当一个程序出错造成系统死锁时,可以切换到其它虚拟控制台工作关闭这个程序。此时使用的命令就是kill,因为kill是大多数Shell内部命令可以直接调用的。

5)应用实例
(1)强行中止(经常使用杀掉)一个进程标识号为324的进程:
#kill -9 324

(2)解除Linux系统的死锁

Linux中有时会发生这样一种情况:一个程序崩溃,并且处于死锁的状态。此时一般不用重新启动计算机,只需要中止(或者说是关闭)这个有问题的程序即可。当kill处于X-Window界面时,主要的程序(除了崩溃的程序之外)一般都已经正常启动了。此时打开一个终端,在那里中止有问题的程序。比如,如果Mozilla浏览器程序出现了锁死的情况,可以使用kill命令来中止所有包含有Mozolla浏览器的程序。首先用ps命令查找该程序的
PID,然后使用kill命令停止这个程序:
#kill -SIGKILL XXX
其中,XXX是包含有Mozolla浏览器的程序的进程标识号。

(3)使用命令回收内存
我们知道内存对于系统是非常重要的,回收内存可以提高系统资源。kill命令可以及时地中止一些"越轨"的程序或很长时间没有相应的程序。例如,使用top命令发现一个无用
(Zombie) 的进程,此时可以使用下面命令:
#kill -9 XXX
其中,XXX是无用的进程标识号。

然后使用下面命令:
#free
此时会发现可用内存容量增加了。

(4)killall命令
Linux下还提供了一个killall命令,可以直接使用进程的名字而不是进程标识号,例如:
# killall -HUP inetd