Android内核剖析(txt+pdf+epub+mobi电子书下载)


发布时间:2020-09-07 15:36:32

点击下载

作者:柯元旦

出版社:电子工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Android内核剖析

Android内核剖析试读:

内容简介

本书详细分析了Android内核的内部机制,包括窗口管理系统、Activity管理系统、输入法框架、编译系统等,为Android内核定制及高级应用程序开发提供技术参考。

书中提及“附图”请到http://www.broadview.com.cn/14398下载。

本书适合于所有Android相关的工程师及产品经理,还可作为相关培训机构的教材。未经许可,不得以任何方式复制或抄袭本书之部分或全部内容。版权所有,侵权必究。图书在版编目(CIP)数据Android内核剖析/柯元旦著. —北京:电子工业出版社,2011.9ISBN 978-7-121-14398-4Ⅰ.①A… Ⅱ.①柯… Ⅲ.①移动终端-应用程序-程序设计 Ⅳ.①TN929.53中国版本图书馆CIP数据核字(2011)第168438号策划编辑:符隆美责任编辑:高洪霞特约编辑:赵树刚印  刷:北京天宇星印刷厂装  订:三河市鹏成印业有限公司出版发行:电子工业出版社     北京市海淀区万寿路173信箱 邮编100036开  本:860×1092  1/16  印张:38.5  字数:1109千字印  次:2011年9月第1次印刷印  数:5000册  定价:79.90元

凡所购买电子工业出版社图书有缺损问题,请向购买书店调换。若书店售缺,请与本社发行部联系,联系及邮购电话:(010)88254888。

质量投诉请发邮件至zlts@phei.com.cn,盗版侵权举报请发邮件至dbqq@phei.com.cn。

服务热线:(010)88258888。前  言FOREWORD“内核剖析”乍一听起来挺吓唬人的,但这个词语存在两个问题,第一个是什么才能称为内核?另一个是“谁”才有能力或者有机会写一本“内核剖析”的书?

本书之所以在前言中提出这个问题,就是为了不吓唬大家,并给大家一种信心,相信自己有能力理解本书的内容。

首先来回答第一个问题,什么才能称为内核?大家都知道,Linux内核的本质包含了线程调度、内存管理及输入/输出管理,那么请问Windows操作系统的内核是什么呢?我们常说,苹果的操作系统Mac OS X的内核是基于UNIX的,那么可以说Mac OS的内核是UNIX吗?

如果仅从线程调度、内存管理,以及输入/输出的角度来区分Windows和Mac OS系统的话,能很明显地感觉到缺少点什么,那就是图形用户接口(GUI),Android、Windows、Mac OS三者的操作方式完全不同,因此,对于图形操作系统而言,本人倾向于将GUI也划归到内核的范畴,这也就是为什么本书使用“内核”作为标题的原因。本书所谓的“内核剖析”的核心也正在于Android所设计的GUI框架的内部原理。Android操作系统是基于Linux实现的,本书并不是去剖析Linux。

下面再来回答第二个问题,即“谁”才有能力或者有机会写一本“内核剖析”的书?如果有人告诉你,一个非微软公司的技术人员写了一本Windows操作系统内核剖析的书,你信吗?反正我不信,原因是,没有阅读过Windows内核源码的人是不可能写出这样的书的,幸运的是Android的源码是开放的。可是源码开放就一定能写这样一本书吗?

在本书截稿时,我未曾见过一本真正分析Android内核的书,大多数书籍都是关于Android SDK应用开发的。在过去的工作经历中,常常遇到一些同事,由于对Android内核不了解,导致在应用程序开发时遇到一些无法解决的问题。遗憾的是,IT类优秀书籍本来就很少,中文原创的更少,Android领域的几乎没有,本人之前也写过一本《Android程序设计》,坦白地讲,当我对Android内核彻底剖析后,觉得那本书有“误人子弟”的成分。因此,我才决定要将自己对Android的理解分享给更多的读者。

那么,我有可能写出一本真正的“内核剖析”的书吗?

我2003年毕业于西安电子科技大学通信工程学院,毕业后与两名同学一起创业,当时我们的目标是做一个“心情播放器”,其本质是一个彩屏多媒体掌上设备,当初想把它做成一个能够根据人的心情自动播放音乐的设备,不谈产品,仅从技术的角度来讲,我们基于美国德州仪器(TI)公司的一款DSP处理器完成了“心情播放器”的设计,包括软件和硬件,该软件系统包括支持最多16个线程的多线程管理、内存管理、FAT16文件系统、GUI子系统,以及一套标准应用程序开发框架、桌面程序等,在这里要再次感谢同宿舍的陈静军同学,他是我到目前为止见过的写代码最优秀的人,在这个项目中,静军设计了这个操作系统的内核及GUI子系统,而我设计了硬件主板、驱动、系统开发框架等,说到这里,如果静军来写一本内核剖析的书,肯定会比我写得更好,在当初设计操作系统前,由于静军还没有加入到我们团队,我才花时间研究了嵌入式操作系统,并设计了一些简单的接口,而当静军加入后,这些工作就由他完成了,因此,从严格意义上讲,我并没有实际编写过操作系统内核代码,只不过从硬件、驱动、系统等不同层面设计了一个系统框架而已。

在这个项目中,一切只是从一颗处理器入手,没有基于任何代码,所有底层代码都是我们编写的,包括汇编和C语言程序设计,因此,在这个过程中,我彻底了解了C语言如何被编译成汇编代码,以及特定处理器如何影响上层的C程序。

当然,这个故事是以失败而告终的,后来我继续从事嵌入式产品设计,包括使用TI高性能DSP处理器、x86处理器,ARM处理器等,不过,仅过了两年时间,又去从事互联网产品的设计,并开始使用Java、C++、PHP、JavaScript、Erlang等不同语言进行软件开发,在使用各种语言时,我常常思考这些语言与底层系统的关系,并从编译原理的角度来理解每一种语言,从而能够理解不同语言的运行环境和操作系统的关系。

直到Android的诞生,我当时对Android的描述是,这是一个把嵌入式系统和互联网应用集合在一起的一个技术。幸运的是这些我都还算熟悉,因此就开始了Android的开发,最开始的时候仅仅是应用程序的开发,虽然也常常考虑Android底层的问题,但由于没有源码,所以也就没有仔细研究,后来发现,这也是一件好事,因为如果不熟悉上层的开发接口,则很难理解内核的一些概念。

后来,应用层积累得差不多了,源码也开放了,于是我就迫不及待地开始了内核之旅,所有的分析都是基于源码的阅读和测试,中间的过程的确是辛苦的,包括在Ubuntu及Mac OS上建立编译环境、思考Android中的异步调度架构、平衡工作和学习的时间等,早上坐地铁也常常看Google groups中关于Android的各种问答。不过,每当你明白一个大的架构的关键之处时,也是一件很开心的事情。

谈及以上履历的目的在于启发正在读大学的朋友,一名电子工程师一定要理论、硬件、软件及梦想同时具备,不要把自己区分为“硬件工程师”、“软件工程师”,我们可以称自己为电子工程师或者“梦想家”。另外,学习一定要循序渐进,如果你还不了解微机原理,那么就不要学习C语言,如果你还不了解数字电路,那么就不要学习微机原理,上层的软件开发需要对底层基础知识的理解,只有这样才能成为一名创造者,并设计出卓越的产品。

多么希望我们中国的大学生在不久的将来也能创造出像Google、Microsoft、Facebook这样著名的企业。内容介绍

本书内容分为五大部分,分别如下:

第1部分,基础篇。因为Android内核研究必须基于Unix-Like的主机系统上,常见的有Ubuntu和Mac OS X,因此,该部分介绍Linux的一些基础知识,以及在Linux上管理源码的工具git。

第2部分,内核篇。Android内核的核心就是一套GUI系统。该部分主要包含视图的内部工作机制及视图管理器(Window Manager Service)和Activity管理器(Activity Manager Service)的内部工作机制。

第3部分,系统篇。内核不等于操作系统,Android是一个操作系统,因此,除了内核之外,还必须定义一套系统架构,比如应用程序的格式定义,以及应用程序如何被安装和卸载、输入法框架等,有时候这部分内容也叫做外壳(Shell)。

第4部分,编译篇。Android相关的源码据说超过1000万行,这套源码由众多的子项目组成,因此,联合编译这些子项目就是一个复杂的问题。Android源码中定义了一套编译框架,该框架可以方便地编译不同类型的子项目,比如一个动态链接库项目、Jar包项目等。了解该套编译架构后,就可以自由地在源码中添加需要的子项目,并控制系统中已有子项目的编译过程。

第5部分,硬件驱动篇。Android目前最成功的产品当然就是智能手机,但同时由于Android开源的特点,也就可以应用于其他一些特定的产品,比如玩具、学习机、税控机、门禁系统等,因此,该部分介绍了一款硬件开源的Android开发板卡。本来,该部分内容还包括OpenGL框架、多媒体框架及Android硬件抽象层(HAL)三方面内容,但由于出版时间原因,暂未包含,本书下一版将包含这些内容。读者对象

本书适合于五类读者。

第一类,开发过Android应用程序的工程师。如果你刚开始接触Android,那么这本书可能会很难理解,建议去Android官方网站用两周的时间学习基本的Android应用程序开发,或者去看本人早期创作的《Android程序设计》一书,但要带着怀疑的态度去读。

第二类,Android技术相关的产品经理。对于产品经理而言,了解项目的技术难度及技术可行性,将有助于制定产品开发时间表。虽然产品经理不需要详细了解技术如何实现,但起码应该知道产品技术的复杂度。

第三类,有扎实的开发经验,却未曾接触过Android的开发人员。系统框架的表面尽管各有千秋,但其内涵却不会差别太大,对于有扎实开发经验的朋友而言,只需要重新了解一下Android中的新概念,就能快速地将这些新概念与已有的知识融合起来,这样,便可以节省大量的时间。

第四类,正在基于iOS开发的工程师。本人最近正在研究iOS的开发,令人惊讶的是iOS和Android开发框架是如此相似。Object-C语言和Java语言的语法虽然差别较大,但其思想却很相似,包括单继承、动态性、内存回收机制等。iOS和Android的Framework也惊人相似,比如都使用sqlite进行数据存储,也使用Preference进行参数存储;视图系统的API接口也类似的地方,都可以使用OpengGL进行界面绘制。当然,iOS和Android视图系统还是有一定的差别,比如iOS中每一个View对象都有两个Layer,从而可以方便地使用OpenGL绘制任何一个View对象,而Android却只有一个,所以Android的动画效果没有iOS那样灵活。遗憾的是iOS不是开源的,因此,我们没有机会去了解iOS内部的详细机制,不过既然iOS和Android有这么多相似的地方,那么就可以通过了解Android的内核机制去思考iOS的一些特性。

第五类,想要编写一个GUI子系统的学生。Android虽然更多地用于手机产品,但其内部的GUI子系统的实现却是一种通用的思路,因此,可以完全抛开Android的系统特性,而仅仅去研究其GUI子系统的实现思路,有了这种思路就可以使用各种语言设计自己想要的GUI子系统。

欢迎朋友们与我进行进一步的交流,我的E-mail是yuandanke@gmail.com。作 者第1部分 基础篇

第1章 Linux基础

第2章 Java基础

第3章 Android源码下载及开发环境配置

第4章 使用git第1章 Linux基础

Android Framework的研究和开发必须在Unix-like(和Unix很像)的主机系统上进行,常用的主机平台包括Ubuntu和Mac OS。另外,Android的底层任务管理及驱动都是基于Linux系统,所以,本书第一章首先来介绍一些Linux的基础知识。如果读者已经熟悉Linux系统,则可以跳过本章。1.1 Linux文件系统概述

估计大多数读者最初使用的都是Windows操作系统,并习惯了Windows中的文件系统。在以往的概念中,文件系统有以下特点:

• 文件系统是由文件及目录组成。

• 每个目录或者文件在磁盘上都对应了一定的存储空间。

• 每个目录或者文件都可以被复制或者删除,除了一些只读的系统文件外。

• 如果有多个存储实体,比如磁盘、U盘,那么,它们将对应多个并列的、不同的文件系统。

• 文件系统有不同的类型,比如早期的FAT16,以及后来的FAT32、NTFS等。

而在Linux系统中,文件系统的概念却与之有较大的差别。现在请开启电脑,一定要是Unix-like的系统,然后开启一个Terminal,就是很像Windows中的DOS界面的一个终端程序,并执行以下命令:

第一个命令用于跳转到根目录,第二个命令用于列出当前目录下的所有文件。如果该目录下包含隐藏文件,则可以使用ls -a命令,参数-a用于显示所有文件。在Unix-like系统中,根目录一般包含如表1-1所示的目录。表1-1 Linux系统根目录结构

Unix-like系统中“文件系统”的概念包含两个意思,第一是“根文件系统”,第二是“存储类文件系统”。后者的概念基本等同于Windows操作系统,而前者则与Windows差别较大,它并不是用于存储实际文件的。本节就来讨论“根文件系统”的概念,根文件系统简称rootfs(Root File System),它有如下特点。

第一,“文件”不仅是指硬盘上的数据,它还包括任何设备资源。在Unix-like系统中,所有的硬件设备都被看做是文件,“文件”是内核范畴的概念,磁盘、U盘、内存、网络,甚至CPU都被内核抽象为“文件”。为了区别于一般意义上的文件,内核级别的文件被称为“设备文件”或“设备虚拟文件”,这些设备文件在rootfs目录中可以被看到,表面上就像Windows系统中的磁盘文件。

第二,并不是所有的目录或文件都对应磁盘上的存储空间。比如,sys、proc、dev这三个目录,它们对应的不是存储空间,而是设备文件,这三个目录中的内容由内核及相应的驱动程序维护。

第三,“存储类文件系统”不能和rootfs并列存在,而只能挂载到rootfs下的一个子目录上,这与Windows系统中的文件系统完全不同。新建一个目录,然后把一个磁盘中的文件系统和这个目录连接起来,这在Windows系统中是不可想象的,而在Unix-like系统中,这却是标准的挂载一个“存储类文件系统”的方法。

第四,Unix-like中“存储类文件系统”内部则等同于Windows中的文件系统,包括文件系统类型。Windows系统中常见的文件系统类型包括FAT16、FAT32、NTFS, Linux系统中也支持这些文件系统类型,但更常见的却是ext2、ext3、ext4、yaffs等。

Unix-like系统中,操作系统只能有一个根文件系统,但可以包含多个“存储类文件系统”。假设,某Linux系统根目录下的home目录中有以下三个文件路径:

此时有一个磁盘,该磁盘上有三个分区,如果在Windows系统中查看该磁盘的话,其内部包含E、F、 G三个磁盘。而在Linux中,则可以把这三个分区分别挂载到以上三个路径下,从而,用户会在以上三个路径下查看到和Windows系统下E、F、G三个分区完全相同的内容。唯一的区别是,在Linux中用户不能通过这三个文件夹来查看磁盘的信息,而在Windows系统中,用户是可以通过E、F、G直接查看磁盘信息的。

执行挂载、卸载“存储文件系统”的操作可以在Terminal下使用mount和umount命令。1.2 Linux启动过程

Linux启动过程对于初学者而言有点扑朔迷离,这是因为启动过程关乎处理器配置、内存配置、外围硬件配置,而不同的处理器和硬件系统会采用不同的策略,从而具体的启动过程会有所差异。但无论差异如何,从计算机系统的角度来看,启动过程一般分为三个步骤,如图1-1所示。图1-1 通用系统的启动过程

首先是开机,开机就是给系统开始供电,此时硬件电路会产生一个确定的复位时序,保证CPU是最后一个被复位的器件。为什么CPU要最后被复位呢?因为,如果CPU第一个被复位,则当CPU复位后开始运行时,其他硬件内部的寄存器状态可能还没有准备好,比如磁盘或者内存,那么就可能出现外围硬件初始化错误。

当正确完成复位后,CPU开始执行第一条指令,该指令所在的内存地址是固定的,这由CPU的制造者指定。不同的CPU可能会从不同的地址获取指令,但这个地址必须是固定的,这个固定地址所保存的程序往往被称为“引导程序”(Bootloader),因为其作用是装载真正的用户程序。

至于如何装载,则是一个策略问题,不同的CPU会提供不同的装载方式,比如有的是通过普通的并口存储器,有的则是通过SD卡,还有的是通过RS232接口。无论硬件上使用何种接口装载,装载过程必须提供以下信息,具体包括:

• 从哪里读取用户程序?

• 用户程序的长度是多少?

• 装载完用户程序后,应该跳转到哪里,即用户程序的执行入口在哪里?

不同硬件系统会采用不同的策略,但只要以上三个信息是确定的,用户程序就会被装载到确定的地址,并执行相同的操作。

第二步是执行内核程序,这里所说的内核程序在上一步中指的就是“用户程序”。因为从CPU的角度来看,除Bootloader之外的所有的程序都是用户程序,只是从软件的角度来看,用户程序被分为“内核程序”和“应用程序”,而本步执行的是“内核程序”。

内核程序初始化时执行的操作包括,初始化各种硬件,包括内存、网络接口、显示器、输入设备,然后建立各种内部数据结构,这些数据结构将用于多线程调度及内存的管理等。当内核初始化完毕后,就开始运行具体的应用程序了。在一般情况下,习惯于将第一个应用程序称为“Home程序”。

第三步就是运行Home程序,比如Windows系统的桌面,就是一个典型的Home程序。之所以称其为Home程序,是因为通过该程序可以方便地启动其他应用程序。而传统的Linux系统启动后,第一个运行程序一般是一个Terminal,尽管它表面上就像一个Dos界面,但它也可以被称为Home程序,因为Home程序设计的目标就是提供一个入口,用户可以通过该入口启动其他应用程序。

以上从通用操作系统的角度介绍了启动过程,接下来,具体来看Android所使用的Linux内核的启动过程。因为目前的Android系统多运行在ARM处理器之上,因此,下面主要分析运行于ARM处理器上的Linux的启动过程。在介绍之前,先来简单区分三个概念:ARM、处理器、CPU。

ARM本身是一个公司的名称,从技术的角度来看,它又是一种微处理器内核的架构。

处理器是一种统称,可以指具体的CPU芯片,比如Intel 8086处理器,苹果的A8处理器等。处理器内部一般包含CPU、片上内存、片上外设接口等不同的硬件逻辑。

CPU是处理器内部的中央处理单元的缩写,CPU可以按照类型分为短指令集架构和长指令集架构两大类,ARM属于短指令集架构的一种。

对于ARM处理器,当复位完毕后,处理器首先执行其片上ROM中的一小块程序。这块ROM的大小一般只有几KB,该段程序就是Bootloader程序,这段程序执行时会根据处理器上一些特定引脚的高低电平状态,选择从何种物理接口上装载用户程序,比如USB口、串口、SD卡、并口Flash等。

多数基于ARM的实际硬件系统,会从并口NAND Flash芯片中的0x00000000地址处装载程序。对于一些小型嵌入式系统而言,该地址中的程序就是最终要执行的用户程序;而对于Android而言,该地址中的程序还不是Android程序,而是一个叫做uboot或者fastboot的程序,其作用是初始化硬件设备,比如网口、SDRAM、RS232等,并提供一些调试功能,比如向NAND Flash中写入新的数据,这可用于开发过程中的内核烧写、升级等。

当uboot(fastboot)被装载后便开始运行,它一般会先检测用户是否按下了某些特别按键,这些特别按键是uboot在编译时预先约定好的,用于进入调试模式。如果用户没有按这些特别的按键,则uboot会从NAND Flash中装载Linux内核,装载的地址是在编译uboot时预先约定好的。

Linux内核被装载后,就开始进行内核初始化的过程,该过程如表1-2所示。表1-2 Linux内核的启动步骤(续表)

以上过程中,init.rc文件在Android手机中的系统根目录下,可以使用adb pull命令提取出该文件:

init.rc的内容格式类似于一种脚本,但是它却不是标准的Linux脚本,而是仅用于启动的脚本。关于init.rc的完整格式请参考Linux相关文档。1.3 常用Linux 命令

Linux中的命令非常多,本节仅介绍一些在开发Android过程中常用的Linux命令。

• man

man的含义是manual,即手册。当我们不清楚某个Linux命令的作用和用法时,可以使用man command进行查询,command为具体的命令名称,比如man ls。

• find

find命令用于查找某个文件或者文件夹,比如:

该命令用于查找当前目录下扩展名为Java的所有文件,find命令后面的“点”代表当前目录,*为通配符,代表任何名称。

• grep

grep命令为正则表达式匹配命令,该命令用于字符串匹配。比如,想查找hello.java文件中包含“Activity”字符串的所有地方,可使用如下命令。

grep和find的区别在于,find用于查找目录或者文件,而grep用于查找指定的字符串,并且字符串可以由正则表达式描述。关于正则表达式请参考其他相关资料。

• xargs。

确切的说,xargs并不是一个命令,而是一个标识,代表了上一个命令的执行结果,并作为下一个命令的参数。Linux命令可以流水线执行,也叫做“多管道”执行,即两个命令用“|”分隔符隔开。比如,想查找当前目录下文件名中包含“oa”的所有文件,可使用以下命令:

该命令中ls用于列出所有文件,“多管道”后面的命令把前面命令的输出结果作为后面命令的参数。

再举一个例子,想查找当前目录下所有包含“Activity”字符串的Java文件,命令如下:

再举例,想查找当前目录下子目录名称为res下的所有.xml文件,并且列出这些.xml文件中包含“status_bar_size”字符串的地方。注意,本例的限制条件是,查找的是res目录下的.xml文件,而不是所有的.xml文件。命令如下:

该命令中,find命令进行了嵌套使用,内部find包含在“`”符号之中。注意这不是单引号,而是键盘上数字键1左边对应的那个符号。内嵌的find命令用于查找名称为res的目录或文件,外部的find命令从得到的这些目录下继续查找.xml文件,“多管道”后面的命令用于查找指定的字符串。

• cat。

cat命令用于连接文件内容并在Terminal中输出文件内容,该命令后面如果只有一个文件名称,则仅输出该文件内容。cat参数中的文件可以是普通意义上的有存储空间的文件,也可以是Linux系统中的设备文件。比如,可以查看当前目录下main.java的文件内容,使用如下命令:

也可以查看设备文件,以下命令用于查看/dev/disk0的内容:

该命令中sudo的含义是使用管理员权限执行后续的命令,因为有些命令要求有管理员的权限。

• chmod。

在Linux系统中,文件的访问者被划分为三类,并针对这三类用户指定不同的访问权限。这三类访问者是:

• user (u),用户自身,即创建该文件的用户。

• group (g),用户所在组,即与创建在一个组里面的用户。

• other (o),其他用户。

chmod命令就是用于设置这三类访问者对某文件的访问权限。访问权限分为读(r)权限、写(w)权限、执行(x)权限,文件类型不同,“执行”的含义不同。可以通过ls -l命令查看文件的访问权限,Linux系统使用10位(bit)数据表示访问的权限,比如某文件的访问权限如下。

• bit 0:使用 - 或者 d 表示,前者表示这是一个文件,后者表示这是一个目录(directory)。

• bit 1~bit 3:用户自身(user)对该文件的访问权限。

• bit 4~bit 6:用户组(group)对该文件的访问权限。

• bit 7~bit 9:其他用户(other)对该文件的访问权限。

举例,某个文件的属性为-rwxrwx---,这表示它是个文件,用户对该文件拥有读取、写入、执行权限,用户组对该文件也拥有读取、写入、执行权限,而其他用户则不能读取、不能写入、不能执行。

再举一个例子,dr-x--x---表示它是一个文件夹。用户对该文件夹拥有读取、执行权限,但不能修改;用户组对该文件拥有执行权限,即只能打开该文件夹,但不能读取和修改;其他用户则不能读取、不能修改,也不能打开该文件夹。

下面来看chmod命令如何修改文件的访问权限。假设有一个脚本文件copy.sh,创建该文件时,默认的访问权限不包括执行(x),但要运行该脚本,用户必须拥有对该文件的执行权限,于是使用以下命令为用户添加执行权限:

命令中u+x的含义是给user添加执行(x)的权限,类似的也可以是o+x、o+rw、g+rwx等。为了便于使用,可以用a代表三类用户,比如a+x、a+rwx等,这里的a代表all,即所有三类用户。

对于某些Linux系统,比如Android手机底层的Linux,chmod命令不识别r、w、x这样的参数,而只能使用8进制数字值来表示,比如:

其中的777为8进制的数,对应的二进制数据为111 111 111,这就分别代表了u、g、o三类用户的访问权限。

• ps,kill。

ps用于列出当前运行的所有进程,kill用于杀死某个进程。这两个命令多用于系统调试,比如,可以先用ps列出所有进程,从输出信息中得到每个进程的id值,即pid,然后调用kill -9 pid,就可以杀死指定pid对应的进程。-9是一个参数,详情可使用man kill查看。

• export。

该命令用于将某个变量值的作用域设为全局范围。比如,可以将某个路径赋值给系统环境变量PATH,然后再export PATH,从而,其他所有程序都可以使用该路径。

该命令还有另外一个巧用。有些公司为了资产管理的需求,往往会给每一台PC机进行编号、命名,比如xxxcom_yyypart_username,这就导致打开Terminal后提示符之前的字符串太长。此时,可以使用export PS1=me命令,PS1一般代表了当前Terminal,等号后面的字符串则任由用户定制,它将代替那串冗长的提示符。执行完后,用户会发现Terminal变得简单多了。1.4 Shell脚本备忘

要全面介绍Shell脚本需要单独的一本书,而这不是本书,这就是为什么本节名称中使用“备忘”的原因。本节主要介绍脚本的基本概念及常用内容,以做个备忘,供以后参考。

读者常常会听到“脚本”这个词语,比如JavasCript被称之为Java脚本(尽管这与Java语言没有丝毫关系),PHP语言也被称为PHP脚本,那么,到底什么是脚本?

脚本的英文是script,该单词的含义是“剧本”的意思,即“一场戏的演出流程”。脚本本身不代表任何计算机语言,也不属于任何计算机语言的范畴,但到目前为止,人们往往把那种不需要编译的程序文件称之为脚本。举个反例,C语言在执行前必须要经过编译、链接,然后才能执行,所以它不是脚本,Java语言也需要编译,因此也不是脚本,而对于JavasCript语言,它的代码是不需要编译的,而是被“解释”执行,脚本运行时需要一个“解释器”,解释器能够读懂预先定义好的脚本语法,并执行之。

所有的脚本有两个共同的特点:

脚本内容是字面上可以读懂的文本文件(Human Readable)。

不同的脚本必须由不同的解释器解释执行,而脚本的语法则由解释器的设计者来定义。

在Linux系统中,常用的脚本包括Bash、Perl,本书仅讲解Bash脚本的使用,Perl脚本请参考其他文档。

前面说过,script的本义是“剧本”,因此,可以想象,脚本文件的结构应该是一个流程,剧本中应该包含不同角色要表演的动作。Linux命令其实就是“剧本”中的角色动作,script解释器除了能够导演这些角色外,还定义了一些条件判断语法,角色可以根据不同的条件进行表演,这种条件判断的语法就像C语言中的if/else、switch/case语句,不过具体的使用方法则有所差别。下面是一个简单的脚本文件:

把以上代码保存为一个文本文件,名称为me命令,文件的扩展名可以任意,但常用.sh作为扩展名,意思是shell,或者干脆不要扩展名,因为Linux系统不像Windows那样“在乎”扩展名。保存后,执行chmod a+x me命令,为me添加执行权限,然后,可以在Ternimal中运行该脚本:

在该脚本文件中,第一行#!/bin/bash这个语句是必需的,并且必须在首行,从而操作系统让该文件选择Bash来解释执行脚本文件。如果是Perl脚本,第一行则为#!/bin/perl。

第二行中的echo是一个Linux命令,#后面是注释。

在脚本中可以调用各种Linux命令,因此,脚本的用途非常广泛,凡是需要按一定的次序执行多个Linux命令的场合都可以使用脚本来完成。下面分别介绍脚本中的一些基本语法。1.4.1 获取输入

输入包含三种,第一种是执行脚本时用户的输入;第二种是将前一个脚本的输出作为该脚本的输入;第三种是脚本函数的参数,关于函数参数见后面小节。

用户的输入可以用$n表示,n为1~9自然数,分别代表输入中的第n个参数。比如“echo i love you”,该命令中第一个参数为i,第二个参数为love,第三个为you,参数是以空格或者Tab键分隔的。举例如下:

执行该脚本,输出为:1.4.2 变量定义

就像C语言一样,脚本语言也可以定义变量,但脚本中的变量类型一般比较简单,所以在Bash脚本中的变量没有类型,所有的变量都是字符串。变量不要单独定义,可直接赋值,赋值语句中不能有空格。引用变量时只需在变量前加一个$符号即可。为了避免引用混淆,常常使用双引号包含要引用的变量,如以下代码所示:

该段代码的两次输出分别为bll和all,因为第一句echo语句中引用了变量A,而第二句中则引用了变量All。1.4.3 条件判断

条件判断主要是判断两个字符串是否相等、两个数字是否相等。其语法格式如以下代码所示:

该段代码判断用户输入的第一个参数,如果其值等于“normal”字符串,则显示“this is normal case”,如果第一个参数为空,则显示“no input,ignal ...”。

条件判断语法中需要注意以下几点:

• 每个if语句后面的执行部分必须跟在then后面,这似乎有点多余,但是Bash脚本就是这么规定的。

• 多个判断分支可以使用elif语句。

• 条件语句必须使用fi结束。

• 条件语句中“[”符号后面必须要有一个空格,比如 if [ "$1" = "normal" ]不能写为 if ["$1" = "normal" ],也就是说在“[”和“$1 = normal”之间都必须要有空格。其原因是Bash脚本中“[”符号并不是简单的一个中括弧,而是一个可执行文件(命令),该命令是一个条件判断命令。这个听起来有点奇怪,但如果把“[”想象为一个函数名称,比如test,则该语句可写为if test “#1”= “normal”,这样看起来似乎更容易理解。

在以上代码中,对于第一个条件判断语句if [ "$1" = "normal" ],有人可能会问,是否可以写为 if [ "$1" =“23”],即用数字代替字符串?答案是肯定的,不过实际上并没有用数字代替字符串,这里的“23”加了双引号,因此,会按照字符串处理。如果写成 if [ "$1" = 23 ]是否可以呢?答案也是可以的,但这里使用的依然不是数字,而还是“23”字符串,只是在编码时,为了避免混淆,对于字符串一般都使用双引号,这与C语言中使用字符串是不同的。那么到底如何才能够把23当做数字进行对比呢?答案是使用“-eq”,比如 if [ "$1" –eq“23”],Bash脚本的比较语句中严格区分操作数,字符串的比较和整数的比较使用不同的操作符,如表1-3所示。表1-3 Bash脚本的比较运算符(续表)1.4.4 while []...do... done语句

该语句的作用类似于C语言中的do...while语句,举例如下:

以上脚本的作用是根据用户输入的参数,执行不同内容。

while语句和if语句中的条件判断格式完全相同。read是一个Linux命令,用于提示用户输入并以按回车键(LF)结束输入。输入的内容保存到变量ACTION中,接下来的case语句根据ACTION的值,执行不同的动作。

in本身也是一个Linux命令,每一个case分支用一个具体的值表示,并带一个小括弧,case分支也可以有通配符,即星号,每一个分支的结束符号是两个分号。esac也是一个Linux命令,这里我们可以理解为case语句的结束标识。

要退出整个while循环,可以使用break语句,done语句是整个while语句的结束标识。1.4.5 for循环

Bash中的for循环类似于Java中的foreach语句,for一般和in联合使用,用于从某个集合中逐个取出元素并对其进行操作,如以下代码所示:

该段代码显示in集合中的所有元素,in语句后面紧跟目标集合,X是一个变量名称,for语句的结束标识是done。

再举一个例子,如以下代码所示:

在这段代码中,in集合的来源是Linux ls命令,即当前目录下所有文件。需要注意的是如果要把Linux的某个命令的输出作为集合的输入,或者作为其他命令的输入,需要把该命令包含在“”符号之中,该符号是键盘上!符号左边的那个按键;而如果仅仅是执行某个Linux命令则不需要“”符号,如以上代码最后一句uname,该命令用于显示操作系统的内部名称。

代码中basename和dirname命令用于显示一个字符串中的路径和文件名称。比如,字符串/usr/local/lib/libexpat.so,对应的dirname是/usr/local/lib,对应的basename是libexpat.so。basename和dirname本身并不去检测该文件是否真正存在于磁盘上,而仅仅是针对字符串的操作。

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载